blob: 07ee7d62dcac1ff852626c3dcc745477de1db9ce [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
33#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000034#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
40
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000041// When invoking builtins, we need to record the safepoint in the middle of
42// the invoke instruction sequence generated by the macro assembler.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000043class SafepointGenerator : public PostCallGenerator {
44 public:
45 SafepointGenerator(LCodeGen* codegen,
46 LPointerMap* pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000047 int deoptimization_index)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048 : codegen_(codegen),
49 pointers_(pointers),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000050 deoptimization_index_(deoptimization_index) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051 virtual ~SafepointGenerator() { }
52
53 virtual void Generate() {
54 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
55 }
56
57 private:
58 LCodeGen* codegen_;
59 LPointerMap* pointers_;
60 int deoptimization_index_;
61};
62
63
64#define __ masm()->
65
66bool LCodeGen::GenerateCode() {
67 HPhase phase("Code generation", chunk());
68 ASSERT(is_unused());
69 status_ = GENERATING;
70 CpuFeatures::Scope scope(SSE2);
71 return GeneratePrologue() &&
72 GenerateBody() &&
73 GenerateDeferredCode() &&
74 GenerateSafepointTable();
75}
76
77
78void LCodeGen::FinishCode(Handle<Code> code) {
79 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000080 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000081 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000082 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000083 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000084}
85
86
87void LCodeGen::Abort(const char* format, ...) {
88 if (FLAG_trace_bailout) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000089 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
90 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000091 va_list arguments;
92 va_start(arguments, format);
93 OS::VPrint(format, arguments);
94 va_end(arguments);
95 PrintF("\n");
96 }
97 status_ = ABORTED;
98}
99
100
101void LCodeGen::Comment(const char* format, ...) {
102 if (!FLAG_code_comments) return;
103 char buffer[4 * KB];
104 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
105 va_list arguments;
106 va_start(arguments, format);
107 builder.AddFormattedList(format, arguments);
108 va_end(arguments);
109
110 // Copy the string before recording it in the assembler to avoid
111 // issues when the stack allocated buffer goes out of scope.
112 size_t length = builder.position();
113 Vector<char> copy = Vector<char>::New(length + 1);
114 memcpy(copy.start(), builder.Finalize(), copy.length());
115 masm()->RecordComment(copy.start());
116}
117
118
119bool LCodeGen::GeneratePrologue() {
120 ASSERT(is_generating());
121
122#ifdef DEBUG
123 if (strlen(FLAG_stop_at) > 0 &&
124 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
125 __ int3();
126 }
127#endif
128
129 __ push(ebp); // Caller's frame pointer.
130 __ mov(ebp, esp);
131 __ push(esi); // Callee's context.
132 __ push(edi); // Callee's JS function.
133
134 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000135 int slots = GetStackSlotCount();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136 if (slots > 0) {
137 if (FLAG_debug_code) {
138 __ mov(Operand(eax), Immediate(slots));
139 Label loop;
140 __ bind(&loop);
141 __ push(Immediate(kSlotsZapValue));
142 __ dec(eax);
143 __ j(not_zero, &loop);
144 } else {
145 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000146#ifdef _MSC_VER
147 // On windows, you may not access the stack more than one page below
148 // the most recently mapped page. To make the allocated area randomly
149 // accessible, we write to each page in turn (the value is irrelevant).
150 const int kPageSize = 4 * KB;
151 for (int offset = slots * kPointerSize - kPageSize;
152 offset > 0;
153 offset -= kPageSize) {
154 __ mov(Operand(esp, offset), eax);
155 }
156#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000157 }
158 }
159
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000160 // Possibly allocate a local context.
161 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
162 if (heap_slots > 0) {
163 Comment(";;; Allocate local context");
164 // Argument to NewContext is the function, which is still in edi.
165 __ push(edi);
166 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
167 FastNewContextStub stub(heap_slots);
168 __ CallStub(&stub);
169 } else {
170 __ CallRuntime(Runtime::kNewContext, 1);
171 }
172 RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
173 // Context is returned in both eax and esi. It replaces the context
174 // passed to us. It's saved in the stack and kept live in esi.
175 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
176
177 // Copy parameters into context if necessary.
178 int num_parameters = scope()->num_parameters();
179 for (int i = 0; i < num_parameters; i++) {
180 Slot* slot = scope()->parameter(i)->AsSlot();
181 if (slot != NULL && slot->type() == Slot::CONTEXT) {
182 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
183 (num_parameters - 1 - i) * kPointerSize;
184 // Load parameter from stack.
185 __ mov(eax, Operand(ebp, parameter_offset));
186 // Store it in the context.
187 int context_offset = Context::SlotOffset(slot->index());
188 __ mov(Operand(esi, context_offset), eax);
189 // Update the write barrier. This clobbers all involved
190 // registers, so we have to use a third register to avoid
191 // clobbering esi.
192 __ mov(ecx, esi);
193 __ RecordWrite(ecx, context_offset, eax, ebx);
194 }
195 }
196 Comment(";;; End allocate local context");
197 }
198
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000199 // Trace the call.
200 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000201 // We have not executed any compiled code yet, so esi still holds the
202 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000203 __ CallRuntime(Runtime::kTraceEnter, 0);
204 }
205 return !is_aborted();
206}
207
208
209bool LCodeGen::GenerateBody() {
210 ASSERT(is_generating());
211 bool emit_instructions = true;
212 for (current_instruction_ = 0;
213 !is_aborted() && current_instruction_ < instructions_->length();
214 current_instruction_++) {
215 LInstruction* instr = instructions_->at(current_instruction_);
216 if (instr->IsLabel()) {
217 LLabel* label = LLabel::cast(instr);
218 emit_instructions = !label->HasReplacement();
219 }
220
221 if (emit_instructions) {
222 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
223 instr->CompileToNative(this);
224 }
225 }
226 return !is_aborted();
227}
228
229
230LInstruction* LCodeGen::GetNextInstruction() {
231 if (current_instruction_ < instructions_->length() - 1) {
232 return instructions_->at(current_instruction_ + 1);
233 } else {
234 return NULL;
235 }
236}
237
238
239bool LCodeGen::GenerateDeferredCode() {
240 ASSERT(is_generating());
241 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
242 LDeferredCode* code = deferred_[i];
243 __ bind(code->entry());
244 code->Generate();
245 __ jmp(code->exit());
246 }
247
248 // Deferred code is the last part of the instruction sequence. Mark
249 // the generated code as done unless we bailed out.
250 if (!is_aborted()) status_ = DONE;
251 return !is_aborted();
252}
253
254
255bool LCodeGen::GenerateSafepointTable() {
256 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000257 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000258 return !is_aborted();
259}
260
261
262Register LCodeGen::ToRegister(int index) const {
263 return Register::FromAllocationIndex(index);
264}
265
266
267XMMRegister LCodeGen::ToDoubleRegister(int index) const {
268 return XMMRegister::FromAllocationIndex(index);
269}
270
271
272Register LCodeGen::ToRegister(LOperand* op) const {
273 ASSERT(op->IsRegister());
274 return ToRegister(op->index());
275}
276
277
278XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
279 ASSERT(op->IsDoubleRegister());
280 return ToDoubleRegister(op->index());
281}
282
283
284int LCodeGen::ToInteger32(LConstantOperand* op) const {
285 Handle<Object> value = chunk_->LookupLiteral(op);
286 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
287 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
288 value->Number());
289 return static_cast<int32_t>(value->Number());
290}
291
292
293Immediate LCodeGen::ToImmediate(LOperand* op) {
294 LConstantOperand* const_op = LConstantOperand::cast(op);
295 Handle<Object> literal = chunk_->LookupLiteral(const_op);
296 Representation r = chunk_->LookupLiteralRepresentation(const_op);
297 if (r.IsInteger32()) {
298 ASSERT(literal->IsNumber());
299 return Immediate(static_cast<int32_t>(literal->Number()));
300 } else if (r.IsDouble()) {
301 Abort("unsupported double immediate");
302 }
303 ASSERT(r.IsTagged());
304 return Immediate(literal);
305}
306
307
308Operand LCodeGen::ToOperand(LOperand* op) const {
309 if (op->IsRegister()) return Operand(ToRegister(op));
310 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
311 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
312 int index = op->index();
313 if (index >= 0) {
314 // Local or spill slot. Skip the frame pointer, function, and
315 // context in the fixed part of the frame.
316 return Operand(ebp, -(index + 3) * kPointerSize);
317 } else {
318 // Incoming parameter. Skip the return address.
319 return Operand(ebp, -(index - 1) * kPointerSize);
320 }
321}
322
323
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000324Operand LCodeGen::HighOperand(LOperand* op) {
325 ASSERT(op->IsDoubleStackSlot());
326 int index = op->index();
327 int offset = (index >= 0) ? index + 3 : index - 1;
328 return Operand(ebp, -offset * kPointerSize);
329}
330
331
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000332void LCodeGen::WriteTranslation(LEnvironment* environment,
333 Translation* translation) {
334 if (environment == NULL) return;
335
336 // The translation includes one command per value in the environment.
337 int translation_size = environment->values()->length();
338 // The output frame height does not include the parameters.
339 int height = translation_size - environment->parameter_count();
340
341 WriteTranslation(environment->outer(), translation);
342 int closure_id = DefineDeoptimizationLiteral(environment->closure());
343 translation->BeginFrame(environment->ast_id(), closure_id, height);
344 for (int i = 0; i < translation_size; ++i) {
345 LOperand* value = environment->values()->at(i);
346 // spilled_registers_ and spilled_double_registers_ are either
347 // both NULL or both set.
348 if (environment->spilled_registers() != NULL && value != NULL) {
349 if (value->IsRegister() &&
350 environment->spilled_registers()[value->index()] != NULL) {
351 translation->MarkDuplicate();
352 AddToTranslation(translation,
353 environment->spilled_registers()[value->index()],
354 environment->HasTaggedValueAt(i));
355 } else if (
356 value->IsDoubleRegister() &&
357 environment->spilled_double_registers()[value->index()] != NULL) {
358 translation->MarkDuplicate();
359 AddToTranslation(
360 translation,
361 environment->spilled_double_registers()[value->index()],
362 false);
363 }
364 }
365
366 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
367 }
368}
369
370
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000371void LCodeGen::AddToTranslation(Translation* translation,
372 LOperand* op,
373 bool is_tagged) {
374 if (op == NULL) {
375 // TODO(twuerthinger): Introduce marker operands to indicate that this value
376 // is not present and must be reconstructed from the deoptimizer. Currently
377 // this is only used for the arguments object.
378 translation->StoreArgumentsObject();
379 } else if (op->IsStackSlot()) {
380 if (is_tagged) {
381 translation->StoreStackSlot(op->index());
382 } else {
383 translation->StoreInt32StackSlot(op->index());
384 }
385 } else if (op->IsDoubleStackSlot()) {
386 translation->StoreDoubleStackSlot(op->index());
387 } else if (op->IsArgument()) {
388 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000389 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000390 translation->StoreStackSlot(src_index);
391 } else if (op->IsRegister()) {
392 Register reg = ToRegister(op);
393 if (is_tagged) {
394 translation->StoreRegister(reg);
395 } else {
396 translation->StoreInt32Register(reg);
397 }
398 } else if (op->IsDoubleRegister()) {
399 XMMRegister reg = ToDoubleRegister(op);
400 translation->StoreDoubleRegister(reg);
401 } else if (op->IsConstantOperand()) {
402 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
403 int src_index = DefineDeoptimizationLiteral(literal);
404 translation->StoreLiteral(src_index);
405 } else {
406 UNREACHABLE();
407 }
408}
409
410
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000411void LCodeGen::CallCodeGeneric(Handle<Code> code,
412 RelocInfo::Mode mode,
413 LInstruction* instr,
414 ContextMode context_mode,
415 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000416 ASSERT(instr != NULL);
417 LPointerMap* pointers = instr->pointer_map();
418 RecordPosition(pointers->position());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000419
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000420 if (context_mode == RESTORE_CONTEXT) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000421 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
422 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000423 __ call(code, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000424
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000425 RegisterLazyDeoptimization(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000426
427 // Signal that we don't inline smi code before these stubs in the
428 // optimizing code generator.
429 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
430 code->kind() == Code::COMPARE_IC) {
431 __ nop();
432 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000433}
434
435
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000436void LCodeGen::CallCode(Handle<Code> code,
437 RelocInfo::Mode mode,
438 LInstruction* instr,
439 ContextMode context_mode) {
440 CallCodeGeneric(code, mode, instr, context_mode, RECORD_SIMPLE_SAFEPOINT);
441}
442
443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000445 int argc,
446 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000447 ContextMode context_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000448 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000449 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 RecordPosition(pointers->position());
452
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000453 if (context_mode == RESTORE_CONTEXT) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000454 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
455 }
456 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000457
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000458 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000459}
460
461
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000462void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
463 int argc,
464 LInstruction* instr) {
465 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
466 __ CallRuntimeSaveDoubles(id);
467 RecordSafepointWithRegisters(
468 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
469}
470
471
472void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
473 SafepointMode safepoint_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000474 // Create the environment to bailout to. If the call has side effects
475 // execution has to continue after the call otherwise execution can continue
476 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000477 LEnvironment* deoptimization_environment;
478 if (instr->HasDeoptimizationEnvironment()) {
479 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000480 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000481 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000482 }
483
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000484 RegisterEnvironmentForDeoptimization(deoptimization_environment);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000485 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
486 RecordSafepoint(instr->pointer_map(),
487 deoptimization_environment->deoptimization_index());
488 } else {
489 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
490 RecordSafepointWithRegisters(
491 instr->pointer_map(),
492 0,
493 deoptimization_environment->deoptimization_index());
494 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000495}
496
497
498void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
499 if (!environment->HasBeenRegistered()) {
500 // Physical stack frame layout:
501 // -x ............. -4 0 ..................................... y
502 // [incoming arguments] [spill slots] [pushed outgoing arguments]
503
504 // Layout of the environment:
505 // 0 ..................................................... size-1
506 // [parameters] [locals] [expression stack including arguments]
507
508 // Layout of the translation:
509 // 0 ........................................................ size - 1 + 4
510 // [expression stack including arguments] [locals] [4 words] [parameters]
511 // |>------------ translation_size ------------<|
512
513 int frame_count = 0;
514 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
515 ++frame_count;
516 }
517 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000518 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000519 int deoptimization_index = deoptimizations_.length();
520 environment->Register(deoptimization_index, translation.index());
521 deoptimizations_.Add(environment);
522 }
523}
524
525
526void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
527 RegisterEnvironmentForDeoptimization(environment);
528 ASSERT(environment->HasBeenRegistered());
529 int id = environment->deoptimization_index();
530 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
531 ASSERT(entry != NULL);
532 if (entry == NULL) {
533 Abort("bailout was not prepared");
534 return;
535 }
536
537 if (FLAG_deopt_every_n_times != 0) {
538 Handle<SharedFunctionInfo> shared(info_->shared_info());
539 Label no_deopt;
540 __ pushfd();
541 __ push(eax);
542 __ push(ebx);
543 __ mov(ebx, shared);
544 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
545 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
546 __ j(not_zero, &no_deopt);
547 if (FLAG_trap_on_deopt) __ int3();
548 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
549 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
550 __ pop(ebx);
551 __ pop(eax);
552 __ popfd();
553 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
554
555 __ bind(&no_deopt);
556 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
557 __ pop(ebx);
558 __ pop(eax);
559 __ popfd();
560 }
561
562 if (cc == no_condition) {
563 if (FLAG_trap_on_deopt) __ int3();
564 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
565 } else {
566 if (FLAG_trap_on_deopt) {
567 NearLabel done;
568 __ j(NegateCondition(cc), &done);
569 __ int3();
570 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
571 __ bind(&done);
572 } else {
573 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY, not_taken);
574 }
575 }
576}
577
578
579void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
580 int length = deoptimizations_.length();
581 if (length == 0) return;
582 ASSERT(FLAG_deopt);
583 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000586 Handle<ByteArray> translations = translations_.CreateByteArray();
587 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000588 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
589
590 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000592 for (int i = 0; i < deoptimization_literals_.length(); i++) {
593 literals->set(i, *deoptimization_literals_[i]);
594 }
595 data->SetLiteralArray(*literals);
596
597 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
598 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
599
600 // Populate the deoptimization entries.
601 for (int i = 0; i < length; i++) {
602 LEnvironment* env = deoptimizations_[i];
603 data->SetAstId(i, Smi::FromInt(env->ast_id()));
604 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
605 data->SetArgumentsStackHeight(i,
606 Smi::FromInt(env->arguments_stack_height()));
607 }
608 code->set_deoptimization_data(*data);
609}
610
611
612int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
613 int result = deoptimization_literals_.length();
614 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
615 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
616 }
617 deoptimization_literals_.Add(literal);
618 return result;
619}
620
621
622void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
623 ASSERT(deoptimization_literals_.length() == 0);
624
625 const ZoneList<Handle<JSFunction> >* inlined_closures =
626 chunk()->inlined_closures();
627
628 for (int i = 0, length = inlined_closures->length();
629 i < length;
630 i++) {
631 DefineDeoptimizationLiteral(inlined_closures->at(i));
632 }
633
634 inlined_function_count_ = deoptimization_literals_.length();
635}
636
637
ager@chromium.org378b34e2011-01-28 08:04:38 +0000638void LCodeGen::RecordSafepoint(
639 LPointerMap* pointers,
640 Safepoint::Kind kind,
641 int arguments,
642 int deoptimization_index) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000643 ASSERT(kind == expected_safepoint_kind_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000644 const ZoneList<LOperand*>* operands = pointers->operands();
645 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000646 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000647 for (int i = 0; i < operands->length(); i++) {
648 LOperand* pointer = operands->at(i);
649 if (pointer->IsStackSlot()) {
650 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000651 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
652 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000653 }
654 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000655}
656
657
658void LCodeGen::RecordSafepoint(LPointerMap* pointers,
659 int deoptimization_index) {
660 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000661}
662
663
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000664void LCodeGen::RecordSafepoint(int deoptimization_index) {
665 LPointerMap empty_pointers(RelocInfo::kNoPosition);
666 RecordSafepoint(&empty_pointers, deoptimization_index);
667}
668
669
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
671 int arguments,
672 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000673 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
674 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000675}
676
677
678void LCodeGen::RecordPosition(int position) {
679 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
680 masm()->positions_recorder()->RecordPosition(position);
681}
682
683
684void LCodeGen::DoLabel(LLabel* label) {
685 if (label->is_loop_header()) {
686 Comment(";;; B%d - LOOP entry", label->block_id());
687 } else {
688 Comment(";;; B%d", label->block_id());
689 }
690 __ bind(label->label());
691 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000692 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000693}
694
695
696void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000697 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000698}
699
700
701void LCodeGen::DoGap(LGap* gap) {
702 for (int i = LGap::FIRST_INNER_POSITION;
703 i <= LGap::LAST_INNER_POSITION;
704 i++) {
705 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
706 LParallelMove* move = gap->GetParallelMove(inner_pos);
707 if (move != NULL) DoParallelMove(move);
708 }
709
710 LInstruction* next = GetNextInstruction();
711 if (next != NULL && next->IsLazyBailout()) {
712 int pc = masm()->pc_offset();
713 safepoints_.SetPcAfterGap(pc);
714 }
715}
716
717
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000718void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
719 DoGap(instr);
720}
721
722
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000723void LCodeGen::DoParameter(LParameter* instr) {
724 // Nothing to do.
725}
726
727
728void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000729 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000730 ASSERT(ToRegister(instr->result()).is(eax));
731 switch (instr->hydrogen()->major_key()) {
732 case CodeStub::RegExpConstructResult: {
733 RegExpConstructResultStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000734 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000735 break;
736 }
737 case CodeStub::RegExpExec: {
738 RegExpExecStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000739 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000740 break;
741 }
742 case CodeStub::SubString: {
743 SubStringStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000744 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745 break;
746 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000747 case CodeStub::NumberToString: {
748 NumberToStringStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000749 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750 break;
751 }
752 case CodeStub::StringAdd: {
753 StringAddStub stub(NO_STRING_ADD_FLAGS);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000754 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755 break;
756 }
757 case CodeStub::StringCompare: {
758 StringCompareStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000759 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000760 break;
761 }
762 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000763 TranscendentalCacheStub stub(instr->transcendental_type(),
764 TranscendentalCacheStub::TAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000765 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000766 break;
767 }
768 default:
769 UNREACHABLE();
770 }
771}
772
773
774void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
775 // Nothing to do.
776}
777
778
779void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000780 if (instr->hydrogen()->HasPowerOf2Divisor()) {
781 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000782
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000783 int32_t divisor =
784 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000785
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000786 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000787
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000788 NearLabel positive_dividend, done;
789 __ test(dividend, Operand(dividend));
790 __ j(not_sign, &positive_dividend);
791 __ neg(dividend);
792 __ and_(dividend, divisor - 1);
793 __ neg(dividend);
794 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
795 __ j(not_zero, &done);
796 DeoptimizeIf(no_condition, instr->environment());
797 }
798 __ bind(&positive_dividend);
799 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000800 __ bind(&done);
801 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000802 NearLabel done, remainder_eq_dividend, slow, do_subtraction, both_positive;
803 Register left_reg = ToRegister(instr->InputAt(0));
804 Register right_reg = ToRegister(instr->InputAt(1));
805 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000806
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000807 ASSERT(left_reg.is(eax));
808 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000809 ASSERT(!right_reg.is(eax));
810 ASSERT(!right_reg.is(edx));
811
812 // Check for x % 0.
813 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000814 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000815 DeoptimizeIf(zero, instr->environment());
816 }
817
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000818 __ test(left_reg, Operand(left_reg));
819 __ j(zero, &remainder_eq_dividend);
820 __ j(sign, &slow);
821
822 __ test(right_reg, Operand(right_reg));
823 __ j(not_sign, &both_positive);
824 // The sign of the divisor doesn't matter.
825 __ neg(right_reg);
826
827 __ bind(&both_positive);
828 // If the dividend is smaller than the nonnegative
829 // divisor, the dividend is the result.
830 __ cmp(left_reg, Operand(right_reg));
831 __ j(less, &remainder_eq_dividend);
832
833 // Check if the divisor is a PowerOfTwo integer.
834 Register scratch = ToRegister(instr->TempAt(0));
835 __ mov(scratch, right_reg);
836 __ sub(Operand(scratch), Immediate(1));
837 __ test(scratch, Operand(right_reg));
838 __ j(not_zero, &do_subtraction);
839 __ and_(left_reg, Operand(scratch));
840 __ jmp(&remainder_eq_dividend);
841
842 __ bind(&do_subtraction);
843 const int kUnfolds = 3;
844 // Try a few subtractions of the dividend.
845 __ mov(scratch, left_reg);
846 for (int i = 0; i < kUnfolds; i++) {
847 // Reduce the dividend by the divisor.
848 __ sub(left_reg, Operand(right_reg));
849 // Check if the dividend is less than the divisor.
850 __ cmp(left_reg, Operand(right_reg));
851 __ j(less, &remainder_eq_dividend);
852 }
853 __ mov(left_reg, scratch);
854
855 // Slow case, using idiv instruction.
856 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000857 // Sign extend to edx.
858 __ cdq();
859
860 // Check for (0 % -x) that will produce negative zero.
861 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
862 NearLabel positive_left;
863 NearLabel done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000864 __ test(left_reg, Operand(left_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000865 __ j(not_sign, &positive_left);
866 __ idiv(right_reg);
867
868 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000869 __ test(result_reg, Operand(result_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000870 __ j(not_zero, &done);
871
872 DeoptimizeIf(no_condition, instr->environment());
873 __ bind(&positive_left);
874 __ idiv(right_reg);
875 __ bind(&done);
876 } else {
877 __ idiv(right_reg);
878 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000879 __ jmp(&done);
880
881 __ bind(&remainder_eq_dividend);
882 __ mov(result_reg, left_reg);
883
884 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000885 }
886}
887
888
889void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000890 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000891 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000892 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
893 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
894 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000895
896 Register left_reg = eax;
897
898 // Check for x / 0.
899 Register right_reg = ToRegister(right);
900 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
901 __ test(right_reg, ToOperand(right));
902 DeoptimizeIf(zero, instr->environment());
903 }
904
905 // Check for (0 / -x) that will produce negative zero.
906 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
907 NearLabel left_not_zero;
908 __ test(left_reg, Operand(left_reg));
909 __ j(not_zero, &left_not_zero);
910 __ test(right_reg, ToOperand(right));
911 DeoptimizeIf(sign, instr->environment());
912 __ bind(&left_not_zero);
913 }
914
915 // Check for (-kMinInt / -1).
916 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
917 NearLabel left_not_min_int;
918 __ cmp(left_reg, kMinInt);
919 __ j(not_zero, &left_not_min_int);
920 __ cmp(right_reg, -1);
921 DeoptimizeIf(zero, instr->environment());
922 __ bind(&left_not_min_int);
923 }
924
925 // Sign extend to edx.
926 __ cdq();
927 __ idiv(right_reg);
928
929 // Deoptimize if remainder is not 0.
930 __ test(edx, Operand(edx));
931 DeoptimizeIf(not_zero, instr->environment());
932}
933
934
935void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000936 Register left = ToRegister(instr->InputAt(0));
937 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000938
939 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000940 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000941 }
942
943 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000944 // Try strength reductions on the multiplication.
945 // All replacement instructions are at most as long as the imul
946 // and have better latency.
947 int constant = ToInteger32(LConstantOperand::cast(right));
948 if (constant == -1) {
949 __ neg(left);
950 } else if (constant == 0) {
951 __ xor_(left, Operand(left));
952 } else if (constant == 2) {
953 __ add(left, Operand(left));
954 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
955 // If we know that the multiplication can't overflow, it's safe to
956 // use instructions that don't set the overflow flag for the
957 // multiplication.
958 switch (constant) {
959 case 1:
960 // Do nothing.
961 break;
962 case 3:
963 __ lea(left, Operand(left, left, times_2, 0));
964 break;
965 case 4:
966 __ shl(left, 2);
967 break;
968 case 5:
969 __ lea(left, Operand(left, left, times_4, 0));
970 break;
971 case 8:
972 __ shl(left, 3);
973 break;
974 case 9:
975 __ lea(left, Operand(left, left, times_8, 0));
976 break;
977 case 16:
978 __ shl(left, 4);
979 break;
980 default:
981 __ imul(left, left, constant);
982 break;
983 }
984 } else {
985 __ imul(left, left, constant);
986 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000987 } else {
988 __ imul(left, ToOperand(right));
989 }
990
991 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
992 DeoptimizeIf(overflow, instr->environment());
993 }
994
995 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
996 // Bail out if the result is supposed to be negative zero.
997 NearLabel done;
998 __ test(left, Operand(left));
999 __ j(not_zero, &done);
1000 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001001 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001002 DeoptimizeIf(no_condition, instr->environment());
1003 }
1004 } else {
1005 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001006 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001007 DeoptimizeIf(sign, instr->environment());
1008 }
1009 __ bind(&done);
1010 }
1011}
1012
1013
1014void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001015 LOperand* left = instr->InputAt(0);
1016 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001017 ASSERT(left->Equals(instr->result()));
1018 ASSERT(left->IsRegister());
1019
1020 if (right->IsConstantOperand()) {
1021 int right_operand = ToInteger32(LConstantOperand::cast(right));
1022 switch (instr->op()) {
1023 case Token::BIT_AND:
1024 __ and_(ToRegister(left), right_operand);
1025 break;
1026 case Token::BIT_OR:
1027 __ or_(ToRegister(left), right_operand);
1028 break;
1029 case Token::BIT_XOR:
1030 __ xor_(ToRegister(left), right_operand);
1031 break;
1032 default:
1033 UNREACHABLE();
1034 break;
1035 }
1036 } else {
1037 switch (instr->op()) {
1038 case Token::BIT_AND:
1039 __ and_(ToRegister(left), ToOperand(right));
1040 break;
1041 case Token::BIT_OR:
1042 __ or_(ToRegister(left), ToOperand(right));
1043 break;
1044 case Token::BIT_XOR:
1045 __ xor_(ToRegister(left), ToOperand(right));
1046 break;
1047 default:
1048 UNREACHABLE();
1049 break;
1050 }
1051 }
1052}
1053
1054
1055void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001056 LOperand* left = instr->InputAt(0);
1057 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001058 ASSERT(left->Equals(instr->result()));
1059 ASSERT(left->IsRegister());
1060 if (right->IsRegister()) {
1061 ASSERT(ToRegister(right).is(ecx));
1062
1063 switch (instr->op()) {
1064 case Token::SAR:
1065 __ sar_cl(ToRegister(left));
1066 break;
1067 case Token::SHR:
1068 __ shr_cl(ToRegister(left));
1069 if (instr->can_deopt()) {
1070 __ test(ToRegister(left), Immediate(0x80000000));
1071 DeoptimizeIf(not_zero, instr->environment());
1072 }
1073 break;
1074 case Token::SHL:
1075 __ shl_cl(ToRegister(left));
1076 break;
1077 default:
1078 UNREACHABLE();
1079 break;
1080 }
1081 } else {
1082 int value = ToInteger32(LConstantOperand::cast(right));
1083 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1084 switch (instr->op()) {
1085 case Token::SAR:
1086 if (shift_count != 0) {
1087 __ sar(ToRegister(left), shift_count);
1088 }
1089 break;
1090 case Token::SHR:
1091 if (shift_count == 0 && instr->can_deopt()) {
1092 __ test(ToRegister(left), Immediate(0x80000000));
1093 DeoptimizeIf(not_zero, instr->environment());
1094 } else {
1095 __ shr(ToRegister(left), shift_count);
1096 }
1097 break;
1098 case Token::SHL:
1099 if (shift_count != 0) {
1100 __ shl(ToRegister(left), shift_count);
1101 }
1102 break;
1103 default:
1104 UNREACHABLE();
1105 break;
1106 }
1107 }
1108}
1109
1110
1111void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001112 LOperand* left = instr->InputAt(0);
1113 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001114 ASSERT(left->Equals(instr->result()));
1115
1116 if (right->IsConstantOperand()) {
1117 __ sub(ToOperand(left), ToImmediate(right));
1118 } else {
1119 __ sub(ToRegister(left), ToOperand(right));
1120 }
1121 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1122 DeoptimizeIf(overflow, instr->environment());
1123 }
1124}
1125
1126
1127void LCodeGen::DoConstantI(LConstantI* instr) {
1128 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001129 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001130}
1131
1132
1133void LCodeGen::DoConstantD(LConstantD* instr) {
1134 ASSERT(instr->result()->IsDoubleRegister());
1135 XMMRegister res = ToDoubleRegister(instr->result());
1136 double v = instr->value();
1137 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1138 // do so if the constant is -0.0.
1139 if (BitCast<uint64_t, double>(v) == 0) {
1140 __ xorpd(res, res);
1141 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001142 Register temp = ToRegister(instr->TempAt(0));
1143 uint64_t int_val = BitCast<uint64_t, double>(v);
1144 int32_t lower = static_cast<int32_t>(int_val);
1145 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001146 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001147 CpuFeatures::Scope scope(SSE4_1);
1148 if (lower != 0) {
1149 __ Set(temp, Immediate(lower));
1150 __ movd(res, Operand(temp));
1151 __ Set(temp, Immediate(upper));
1152 __ pinsrd(res, Operand(temp), 1);
1153 } else {
1154 __ xorpd(res, res);
1155 __ Set(temp, Immediate(upper));
1156 __ pinsrd(res, Operand(temp), 1);
1157 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001158 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001159 __ Set(temp, Immediate(upper));
1160 __ movd(res, Operand(temp));
1161 __ psllq(res, 32);
1162 if (lower != 0) {
1163 __ Set(temp, Immediate(lower));
1164 __ movd(xmm0, Operand(temp));
1165 __ por(res, xmm0);
1166 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001167 }
1168 }
1169}
1170
1171
1172void LCodeGen::DoConstantT(LConstantT* instr) {
1173 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001174 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001175}
1176
1177
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001178void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001179 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001180 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001181 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1182}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001183
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001185void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
1186 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001187 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001188 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001189}
1190
1191
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001192void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001193 Register result = ToRegister(instr->result());
1194 Register array = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001195 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001196}
1197
1198
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001200 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001201 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001202 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001203 ASSERT(input.is(result));
1204 NearLabel done;
1205 // If the object is a smi return the object.
1206 __ test(input, Immediate(kSmiTagMask));
1207 __ j(zero, &done);
1208
1209 // If the object is not a value type, return the object.
1210 __ CmpObjectType(input, JS_VALUE_TYPE, map);
1211 __ j(not_equal, &done);
1212 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1213
1214 __ bind(&done);
1215}
1216
1217
1218void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001219 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001220 ASSERT(input->Equals(instr->result()));
1221 __ not_(ToRegister(input));
1222}
1223
1224
1225void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001226 __ push(ToOperand(instr->InputAt(0)));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001227 CallRuntime(Runtime::kThrow, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001228
1229 if (FLAG_debug_code) {
1230 Comment("Unreachable code.");
1231 __ int3();
1232 }
1233}
1234
1235
1236void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001237 LOperand* left = instr->InputAt(0);
1238 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001239 ASSERT(left->Equals(instr->result()));
1240
1241 if (right->IsConstantOperand()) {
1242 __ add(ToOperand(left), ToImmediate(right));
1243 } else {
1244 __ add(ToRegister(left), ToOperand(right));
1245 }
1246
1247 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1248 DeoptimizeIf(overflow, instr->environment());
1249 }
1250}
1251
1252
1253void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001254 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1255 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1256 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001257 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001258 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001259 switch (instr->op()) {
1260 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001261 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001262 break;
1263 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001264 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001265 break;
1266 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001267 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 break;
1269 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001270 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001271 break;
1272 case Token::MOD: {
1273 // Pass two doubles as arguments on the stack.
1274 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001275 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1276 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 __ CallCFunction(
1278 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1279 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001280
1281 // Return value is in st(0) on ia32.
1282 // Store it into the (fixed) result register.
1283 __ sub(Operand(esp), Immediate(kDoubleSize));
1284 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001285 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001286 __ add(Operand(esp), Immediate(kDoubleSize));
1287 break;
1288 }
1289 default:
1290 UNREACHABLE();
1291 break;
1292 }
1293}
1294
1295
1296void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001297 ASSERT(ToRegister(instr->InputAt(0)).is(edx));
1298 ASSERT(ToRegister(instr->InputAt(1)).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001299 ASSERT(ToRegister(instr->result()).is(eax));
1300
1301 TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001302 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001303}
1304
1305
1306int LCodeGen::GetNextEmittedBlock(int block) {
1307 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1308 LLabel* label = chunk_->GetLabel(i);
1309 if (!label->HasReplacement()) return i;
1310 }
1311 return -1;
1312}
1313
1314
1315void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1316 int next_block = GetNextEmittedBlock(current_block_);
1317 right_block = chunk_->LookupDestination(right_block);
1318 left_block = chunk_->LookupDestination(left_block);
1319
1320 if (right_block == left_block) {
1321 EmitGoto(left_block);
1322 } else if (left_block == next_block) {
1323 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1324 } else if (right_block == next_block) {
1325 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1326 } else {
1327 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1328 __ jmp(chunk_->GetAssemblyLabel(right_block));
1329 }
1330}
1331
1332
1333void LCodeGen::DoBranch(LBranch* instr) {
1334 int true_block = chunk_->LookupDestination(instr->true_block_id());
1335 int false_block = chunk_->LookupDestination(instr->false_block_id());
1336
1337 Representation r = instr->hydrogen()->representation();
1338 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001339 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001340 __ test(reg, Operand(reg));
1341 EmitBranch(true_block, false_block, not_zero);
1342 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001343 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001344 __ xorpd(xmm0, xmm0);
1345 __ ucomisd(reg, xmm0);
1346 EmitBranch(true_block, false_block, not_equal);
1347 } else {
1348 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001349 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001350 if (instr->hydrogen()->type().IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352 EmitBranch(true_block, false_block, equal);
1353 } else {
1354 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1355 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001358 __ j(equal, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001359 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001360 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 __ cmp(reg, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001362 __ j(equal, false_label);
1363 __ test(reg, Operand(reg));
1364 __ j(equal, false_label);
1365 __ test(reg, Immediate(kSmiTagMask));
1366 __ j(zero, true_label);
1367
1368 // Test for double values. Zero is false.
1369 NearLabel call_stub;
1370 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001371 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001372 __ j(not_equal, &call_stub);
1373 __ fldz();
1374 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1375 __ FCmp();
1376 __ j(zero, false_label);
1377 __ jmp(true_label);
1378
1379 // The conversion stub doesn't cause garbage collections so it's
1380 // safe to not record a safepoint after the call.
1381 __ bind(&call_stub);
1382 ToBooleanStub stub;
1383 __ pushad();
1384 __ push(reg);
1385 __ CallStub(&stub);
1386 __ test(eax, Operand(eax));
1387 __ popad();
1388 EmitBranch(true_block, false_block, not_zero);
1389 }
1390 }
1391}
1392
1393
1394void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
1395 block = chunk_->LookupDestination(block);
1396 int next_block = GetNextEmittedBlock(current_block_);
1397 if (block != next_block) {
1398 // Perform stack overflow check if this goto needs it before jumping.
1399 if (deferred_stack_check != NULL) {
1400 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001402 __ cmp(esp, Operand::StaticVariable(stack_limit));
1403 __ j(above_equal, chunk_->GetAssemblyLabel(block));
1404 __ jmp(deferred_stack_check->entry());
1405 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1406 } else {
1407 __ jmp(chunk_->GetAssemblyLabel(block));
1408 }
1409 }
1410}
1411
1412
1413void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001414 PushSafepointRegistersScope scope(this);
1415 CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001416}
1417
1418void LCodeGen::DoGoto(LGoto* instr) {
1419 class DeferredStackCheck: public LDeferredCode {
1420 public:
1421 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1422 : LDeferredCode(codegen), instr_(instr) { }
1423 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1424 private:
1425 LGoto* instr_;
1426 };
1427
1428 DeferredStackCheck* deferred = NULL;
1429 if (instr->include_stack_check()) {
1430 deferred = new DeferredStackCheck(this, instr);
1431 }
1432 EmitGoto(instr->block_id(), deferred);
1433}
1434
1435
1436Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1437 Condition cond = no_condition;
1438 switch (op) {
1439 case Token::EQ:
1440 case Token::EQ_STRICT:
1441 cond = equal;
1442 break;
1443 case Token::LT:
1444 cond = is_unsigned ? below : less;
1445 break;
1446 case Token::GT:
1447 cond = is_unsigned ? above : greater;
1448 break;
1449 case Token::LTE:
1450 cond = is_unsigned ? below_equal : less_equal;
1451 break;
1452 case Token::GTE:
1453 cond = is_unsigned ? above_equal : greater_equal;
1454 break;
1455 case Token::IN:
1456 case Token::INSTANCEOF:
1457 default:
1458 UNREACHABLE();
1459 }
1460 return cond;
1461}
1462
1463
1464void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
1465 if (right->IsConstantOperand()) {
1466 __ cmp(ToOperand(left), ToImmediate(right));
1467 } else {
1468 __ cmp(ToRegister(left), ToOperand(right));
1469 }
1470}
1471
1472
1473void LCodeGen::DoCmpID(LCmpID* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001474 LOperand* left = instr->InputAt(0);
1475 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001476 LOperand* result = instr->result();
1477
1478 NearLabel unordered;
1479 if (instr->is_double()) {
1480 // Don't base result on EFLAGS when a NaN is involved. Instead
1481 // jump to the unordered case, which produces a false value.
1482 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1483 __ j(parity_even, &unordered, not_taken);
1484 } else {
1485 EmitCmpI(left, right);
1486 }
1487
1488 NearLabel done;
1489 Condition cc = TokenToCondition(instr->op(), instr->is_double());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001490 __ mov(ToRegister(result), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001491 __ j(cc, &done);
1492
1493 __ bind(&unordered);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001494 __ mov(ToRegister(result), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001495 __ bind(&done);
1496}
1497
1498
1499void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001500 LOperand* left = instr->InputAt(0);
1501 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 int false_block = chunk_->LookupDestination(instr->false_block_id());
1503 int true_block = chunk_->LookupDestination(instr->true_block_id());
1504
1505 if (instr->is_double()) {
1506 // Don't base result on EFLAGS when a NaN is involved. Instead
1507 // jump to the false block.
1508 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1509 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1510 } else {
1511 EmitCmpI(left, right);
1512 }
1513
1514 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1515 EmitBranch(true_block, false_block, cc);
1516}
1517
1518
1519void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001520 Register left = ToRegister(instr->InputAt(0));
1521 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 Register result = ToRegister(instr->result());
1523
1524 __ cmp(left, Operand(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001526 NearLabel done;
1527 __ j(equal, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529 __ bind(&done);
1530}
1531
1532
1533void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001534 Register left = ToRegister(instr->InputAt(0));
1535 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001536 int false_block = chunk_->LookupDestination(instr->false_block_id());
1537 int true_block = chunk_->LookupDestination(instr->true_block_id());
1538
1539 __ cmp(left, Operand(right));
1540 EmitBranch(true_block, false_block, equal);
1541}
1542
1543
1544void LCodeGen::DoIsNull(LIsNull* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001545 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001546 Register result = ToRegister(instr->result());
1547
1548 // TODO(fsc): If the expression is known to be a smi, then it's
1549 // definitely not null. Materialize false.
1550
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001551 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001552 if (instr->is_strict()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001554 NearLabel done;
1555 __ j(equal, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001556 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001557 __ bind(&done);
1558 } else {
1559 NearLabel true_value, false_value, done;
1560 __ j(equal, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001561 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001562 __ j(equal, &true_value);
1563 __ test(reg, Immediate(kSmiTagMask));
1564 __ j(zero, &false_value);
1565 // Check for undetectable objects by looking in the bit field in
1566 // the map. The object has already been smi checked.
1567 Register scratch = result;
1568 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1569 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1570 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1571 __ j(not_zero, &true_value);
1572 __ bind(&false_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001574 __ jmp(&done);
1575 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001577 __ bind(&done);
1578 }
1579}
1580
1581
1582void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001583 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001584
1585 // TODO(fsc): If the expression is known to be a smi, then it's
1586 // definitely not null. Jump to the false block.
1587
1588 int true_block = chunk_->LookupDestination(instr->true_block_id());
1589 int false_block = chunk_->LookupDestination(instr->false_block_id());
1590
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001591 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001592 if (instr->is_strict()) {
1593 EmitBranch(true_block, false_block, equal);
1594 } else {
1595 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1596 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1597 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 __ j(equal, true_label);
1600 __ test(reg, Immediate(kSmiTagMask));
1601 __ j(zero, false_label);
1602 // Check for undetectable objects by looking in the bit field in
1603 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001604 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001605 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1606 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1607 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1608 EmitBranch(true_block, false_block, not_zero);
1609 }
1610}
1611
1612
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001613Condition LCodeGen::EmitIsObject(Register input,
1614 Register temp1,
1615 Register temp2,
1616 Label* is_not_object,
1617 Label* is_object) {
1618 ASSERT(!input.is(temp1));
1619 ASSERT(!input.is(temp2));
1620 ASSERT(!temp1.is(temp2));
1621
1622 __ test(input, Immediate(kSmiTagMask));
1623 __ j(equal, is_not_object);
1624
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001626 __ j(equal, is_object);
1627
1628 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1629 // Undetectable objects behave like undefined.
1630 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
1631 __ test(temp2, Immediate(1 << Map::kIsUndetectable));
1632 __ j(not_zero, is_not_object);
1633
1634 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
1635 __ cmp(temp2, FIRST_JS_OBJECT_TYPE);
1636 __ j(below, is_not_object);
1637 __ cmp(temp2, LAST_JS_OBJECT_TYPE);
1638 return below_equal;
1639}
1640
1641
1642void LCodeGen::DoIsObject(LIsObject* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001643 Register reg = ToRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001644 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001645 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001646 Label is_false, is_true, done;
1647
1648 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1649 __ j(true_cond, &is_true);
1650
1651 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001652 __ mov(result, factory()->false_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001653 __ jmp(&done);
1654
1655 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001656 __ mov(result, factory()->true_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001657
1658 __ bind(&done);
1659}
1660
1661
1662void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001663 Register reg = ToRegister(instr->InputAt(0));
1664 Register temp = ToRegister(instr->TempAt(0));
1665 Register temp2 = ToRegister(instr->TempAt(1));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001666
1667 int true_block = chunk_->LookupDestination(instr->true_block_id());
1668 int false_block = chunk_->LookupDestination(instr->false_block_id());
1669 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1670 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1671
1672 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
1673
1674 EmitBranch(true_block, false_block, true_cond);
1675}
1676
1677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678void LCodeGen::DoIsSmi(LIsSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001679 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001680 Register result = ToRegister(instr->result());
1681
1682 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1683 __ test(input, Immediate(kSmiTagMask));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685 NearLabel done;
1686 __ j(zero, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001688 __ bind(&done);
1689}
1690
1691
1692void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001693 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001694
1695 int true_block = chunk_->LookupDestination(instr->true_block_id());
1696 int false_block = chunk_->LookupDestination(instr->false_block_id());
1697
1698 __ test(input, Immediate(kSmiTagMask));
1699 EmitBranch(true_block, false_block, zero);
1700}
1701
1702
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001703static InstanceType TestType(HHasInstanceType* instr) {
1704 InstanceType from = instr->from();
1705 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001706 if (from == FIRST_TYPE) return to;
1707 ASSERT(from == to || to == LAST_TYPE);
1708 return from;
1709}
1710
1711
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001712static Condition BranchCondition(HHasInstanceType* instr) {
1713 InstanceType from = instr->from();
1714 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001715 if (from == to) return equal;
1716 if (to == LAST_TYPE) return above_equal;
1717 if (from == FIRST_TYPE) return below_equal;
1718 UNREACHABLE();
1719 return equal;
1720}
1721
1722
1723void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001724 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001725 Register result = ToRegister(instr->result());
1726
1727 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1728 __ test(input, Immediate(kSmiTagMask));
1729 NearLabel done, is_false;
1730 __ j(zero, &is_false);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001731 __ CmpObjectType(input, TestType(instr->hydrogen()), result);
1732 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001733 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001734 __ jmp(&done);
1735 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001737 __ bind(&done);
1738}
1739
1740
1741void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001742 Register input = ToRegister(instr->InputAt(0));
1743 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001744
1745 int true_block = chunk_->LookupDestination(instr->true_block_id());
1746 int false_block = chunk_->LookupDestination(instr->false_block_id());
1747
1748 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1749
1750 __ test(input, Immediate(kSmiTagMask));
1751 __ j(zero, false_label);
1752
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001753 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1754 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001755}
1756
1757
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001758void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1759 Register input = ToRegister(instr->InputAt(0));
1760 Register result = ToRegister(instr->result());
1761
1762 if (FLAG_debug_code) {
1763 __ AbortIfNotString(input);
1764 }
1765
1766 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
1767 __ IndexFromHash(result, result);
1768}
1769
1770
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001771void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001772 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 Register result = ToRegister(instr->result());
1774
1775 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001777 __ test(FieldOperand(input, String::kHashFieldOffset),
1778 Immediate(String::kContainsCachedArrayIndexMask));
1779 NearLabel done;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001780 __ j(zero, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001782 __ bind(&done);
1783}
1784
1785
1786void LCodeGen::DoHasCachedArrayIndexAndBranch(
1787 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001788 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001789
1790 int true_block = chunk_->LookupDestination(instr->true_block_id());
1791 int false_block = chunk_->LookupDestination(instr->false_block_id());
1792
1793 __ test(FieldOperand(input, String::kHashFieldOffset),
1794 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001795 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001796}
1797
1798
1799// Branches to a label or falls through with the answer in the z flag. Trashes
1800// the temp registers, but not the input. Only input and temp2 may alias.
1801void LCodeGen::EmitClassOfTest(Label* is_true,
1802 Label* is_false,
1803 Handle<String>class_name,
1804 Register input,
1805 Register temp,
1806 Register temp2) {
1807 ASSERT(!input.is(temp));
1808 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
1809 __ test(input, Immediate(kSmiTagMask));
1810 __ j(zero, is_false);
1811 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
1812 __ j(below, is_false);
1813
1814 // Map is now in temp.
1815 // Functions have class 'Function'.
1816 __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
1817 if (class_name->IsEqualTo(CStrVector("Function"))) {
1818 __ j(equal, is_true);
1819 } else {
1820 __ j(equal, is_false);
1821 }
1822
1823 // Check if the constructor in the map is a function.
1824 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
1825
1826 // As long as JS_FUNCTION_TYPE is the last instance type and it is
1827 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1828 // LAST_JS_OBJECT_TYPE.
1829 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1830 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
1831
1832 // Objects with a non-function constructor have class 'Object'.
1833 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1834 if (class_name->IsEqualTo(CStrVector("Object"))) {
1835 __ j(not_equal, is_true);
1836 } else {
1837 __ j(not_equal, is_false);
1838 }
1839
1840 // temp now contains the constructor function. Grab the
1841 // instance class name from there.
1842 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1843 __ mov(temp, FieldOperand(temp,
1844 SharedFunctionInfo::kInstanceClassNameOffset));
1845 // The class name we are testing against is a symbol because it's a literal.
1846 // The name in the constructor is a symbol because of the way the context is
1847 // booted. This routine isn't expected to work for random API-created
1848 // classes and it doesn't have to because you can't access it with natives
1849 // syntax. Since both sides are symbols it is sufficient to use an identity
1850 // comparison.
1851 __ cmp(temp, class_name);
1852 // End with the answer in the z flag.
1853}
1854
1855
1856void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001857 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001858 Register result = ToRegister(instr->result());
1859 ASSERT(input.is(result));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001860 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001861 Handle<String> class_name = instr->hydrogen()->class_name();
1862 NearLabel done;
1863 Label is_true, is_false;
1864
1865 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
1866
1867 __ j(not_equal, &is_false);
1868
1869 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001870 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001871 __ jmp(&done);
1872
1873 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001874 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001875 __ bind(&done);
1876}
1877
1878
1879void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001880 Register input = ToRegister(instr->InputAt(0));
1881 Register temp = ToRegister(instr->TempAt(0));
1882 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001883 if (input.is(temp)) {
1884 // Swap.
1885 Register swapper = temp;
1886 temp = temp2;
1887 temp2 = swapper;
1888 }
1889 Handle<String> class_name = instr->hydrogen()->class_name();
1890
1891 int true_block = chunk_->LookupDestination(instr->true_block_id());
1892 int false_block = chunk_->LookupDestination(instr->false_block_id());
1893
1894 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1895 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1896
1897 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1898
1899 EmitBranch(true_block, false_block, equal);
1900}
1901
1902
1903void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001904 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001905 int true_block = instr->true_block_id();
1906 int false_block = instr->false_block_id();
1907
1908 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1909 EmitBranch(true_block, false_block, equal);
1910}
1911
1912
1913void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001914 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001915 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001916 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001917 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001918
1919 NearLabel true_value, done;
1920 __ test(eax, Operand(eax));
1921 __ j(zero, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001922 __ mov(ToRegister(instr->result()), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001923 __ jmp(&done);
1924 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001925 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001926 __ bind(&done);
1927}
1928
1929
1930void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001931 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001932 int true_block = chunk_->LookupDestination(instr->true_block_id());
1933 int false_block = chunk_->LookupDestination(instr->false_block_id());
1934
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001935 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001936 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001937 __ test(eax, Operand(eax));
1938 EmitBranch(true_block, false_block, zero);
1939}
1940
1941
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001942void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1943 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1944 public:
1945 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1946 LInstanceOfKnownGlobal* instr)
1947 : LDeferredCode(codegen), instr_(instr) { }
1948 virtual void Generate() {
1949 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
1950 }
1951
1952 Label* map_check() { return &map_check_; }
1953
1954 private:
1955 LInstanceOfKnownGlobal* instr_;
1956 Label map_check_;
1957 };
1958
1959 DeferredInstanceOfKnownGlobal* deferred;
1960 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1961
1962 Label done, false_result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001963 Register object = ToRegister(instr->InputAt(0));
1964 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001965
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001966 // A Smi is not an instance of anything.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001967 __ test(object, Immediate(kSmiTagMask));
1968 __ j(zero, &false_result, not_taken);
1969
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001970 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001971 // hole value will be patched to the last map/result pair generated by the
1972 // instanceof stub.
1973 NearLabel cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001974 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001975 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
1976 __ bind(deferred->map_check()); // Label for calculating code patching.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001978 __ j(not_equal, &cache_miss, not_taken);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001980 __ jmp(&done);
1981
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001982 // The inlined call site cache did not match. Check for null and string
1983 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001984 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001985 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001987 __ j(equal, &false_result);
1988
1989 // String values are not instances of anything.
1990 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
1991 __ j(is_string, &false_result);
1992
1993 // Go to the deferred code.
1994 __ jmp(deferred->entry());
1995
1996 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001997 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001998
1999 // Here result has either true or false. Deferred code also produces true or
2000 // false object.
2001 __ bind(deferred->exit());
2002 __ bind(&done);
2003}
2004
2005
2006void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2007 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002008 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002009
2010 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2011 flags = static_cast<InstanceofStub::Flags>(
2012 flags | InstanceofStub::kArgsInRegisters);
2013 flags = static_cast<InstanceofStub::Flags>(
2014 flags | InstanceofStub::kCallSiteInlineCheck);
2015 flags = static_cast<InstanceofStub::Flags>(
2016 flags | InstanceofStub::kReturnTrueFalseObject);
2017 InstanceofStub stub(flags);
2018
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002019 // Get the temp register reserved by the instruction. This needs to be a
2020 // register which is pushed last by PushSafepointRegisters as top of the
2021 // stack is used to pass the offset to the location of the map check to
2022 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002023 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002024 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002025 __ mov(InstanceofStub::right(), Immediate(instr->function()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002026 static const int kAdditionalDelta = 16;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002027 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002028 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002029 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002030 CallCodeGeneric(stub.GetCode(),
2031 RelocInfo::CODE_TARGET,
2032 instr,
2033 RESTORE_CONTEXT,
2034 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002035 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002036 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002037}
2038
2039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002040static Condition ComputeCompareCondition(Token::Value op) {
2041 switch (op) {
2042 case Token::EQ_STRICT:
2043 case Token::EQ:
2044 return equal;
2045 case Token::LT:
2046 return less;
2047 case Token::GT:
2048 return greater;
2049 case Token::LTE:
2050 return less_equal;
2051 case Token::GTE:
2052 return greater_equal;
2053 default:
2054 UNREACHABLE();
2055 return no_condition;
2056 }
2057}
2058
2059
2060void LCodeGen::DoCmpT(LCmpT* instr) {
2061 Token::Value op = instr->op();
2062
2063 Handle<Code> ic = CompareIC::GetUninitialized(op);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002064 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065
2066 Condition condition = ComputeCompareCondition(op);
2067 if (op == Token::GT || op == Token::LTE) {
2068 condition = ReverseCondition(condition);
2069 }
2070 NearLabel true_value, done;
2071 __ test(eax, Operand(eax));
2072 __ j(condition, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002073 __ mov(ToRegister(instr->result()), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002074 __ jmp(&done);
2075 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002076 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077 __ bind(&done);
2078}
2079
2080
2081void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
2082 Token::Value op = instr->op();
2083 int true_block = chunk_->LookupDestination(instr->true_block_id());
2084 int false_block = chunk_->LookupDestination(instr->false_block_id());
2085
2086 Handle<Code> ic = CompareIC::GetUninitialized(op);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002087 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002088
2089 // The compare stub expects compare condition and the input operands
2090 // reversed for GT and LTE.
2091 Condition condition = ComputeCompareCondition(op);
2092 if (op == Token::GT || op == Token::LTE) {
2093 condition = ReverseCondition(condition);
2094 }
2095 __ test(eax, Operand(eax));
2096 EmitBranch(true_block, false_block, condition);
2097}
2098
2099
2100void LCodeGen::DoReturn(LReturn* instr) {
2101 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002102 // Preserve the return value on the stack and rely on the runtime call
2103 // to return the value in the same register. We're leaving the code
2104 // managed by the register allocator and tearing down the frame, it's
2105 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002106 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002107 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002108 __ CallRuntime(Runtime::kTraceExit, 1);
2109 }
2110 __ mov(esp, ebp);
2111 __ pop(ebp);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002112 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002113}
2114
2115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002116void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002117 Register result = ToRegister(instr->result());
2118 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
2119 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002120 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002121 DeoptimizeIf(equal, instr->environment());
2122 }
2123}
2124
2125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002126void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2127 ASSERT(ToRegister(instr->context()).is(esi));
2128 ASSERT(ToRegister(instr->global_object()).is(eax));
2129 ASSERT(ToRegister(instr->result()).is(eax));
2130
2131 __ mov(ecx, instr->name());
2132 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2133 RelocInfo::CODE_TARGET_CONTEXT;
2134 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002135 CallCode(ic, mode, instr, CONTEXT_ADJUSTED);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002136}
2137
2138
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002139void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002140 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002141 Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
2142
2143 // If the cell we are storing to contains the hole it could have
2144 // been deleted from the property dictionary. In that case, we need
2145 // to update the property details in the property dictionary to mark
2146 // it as no longer deleted. We deoptimize in that case.
2147 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002149 DeoptimizeIf(equal, instr->environment());
2150 }
2151
2152 // Store the value.
2153 __ mov(cell_operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002154}
2155
2156
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002157void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2158 ASSERT(ToRegister(instr->context()).is(esi));
2159 ASSERT(ToRegister(instr->global_object()).is(edx));
2160 ASSERT(ToRegister(instr->value()).is(eax));
2161
2162 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002163 Handle<Code> ic = instr->strict_mode()
2164 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2165 : isolate()->builtins()->StoreIC_Initialize();
2166 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr, CONTEXT_ADJUSTED);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002167}
2168
2169
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002170void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002171 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002172 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002173 __ mov(result, ContextOperand(context, instr->slot_index()));
2174}
2175
2176
2177void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2178 Register context = ToRegister(instr->context());
2179 Register value = ToRegister(instr->value());
2180 __ mov(ContextOperand(context, instr->slot_index()), value);
2181 if (instr->needs_write_barrier()) {
2182 Register temp = ToRegister(instr->TempAt(0));
2183 int offset = Context::SlotOffset(instr->slot_index());
2184 __ RecordWrite(context, offset, value, temp);
2185 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002186}
2187
2188
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002189void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002190 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002191 Register result = ToRegister(instr->result());
2192 if (instr->hydrogen()->is_in_object()) {
2193 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2194 } else {
2195 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2196 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2197 }
2198}
2199
2200
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002201void LCodeGen::EmitLoadField(Register result,
2202 Register object,
2203 Handle<Map> type,
2204 Handle<String> name) {
2205 LookupResult lookup;
2206 type->LookupInDescriptors(NULL, *name, &lookup);
2207 ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
2208 int index = lookup.GetLocalFieldIndexFromMap(*type);
2209 int offset = index * kPointerSize;
2210 if (index < 0) {
2211 // Negative property indices are in-object properties, indexed
2212 // from the end of the fixed part of the object.
2213 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2214 } else {
2215 // Non-negative property indices are in the properties array.
2216 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2217 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2218 }
2219}
2220
2221
2222void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2223 Register object = ToRegister(instr->object());
2224 Register result = ToRegister(instr->result());
2225
2226 int map_count = instr->hydrogen()->types()->length();
2227 Handle<String> name = instr->hydrogen()->name();
2228 if (map_count == 0) {
2229 ASSERT(instr->hydrogen()->need_generic());
2230 __ mov(ecx, name);
2231 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002232 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002233 } else {
2234 NearLabel done;
2235 for (int i = 0; i < map_count - 1; ++i) {
2236 Handle<Map> map = instr->hydrogen()->types()->at(i);
2237 NearLabel next;
2238 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2239 __ j(not_equal, &next);
2240 EmitLoadField(result, object, map, name);
2241 __ jmp(&done);
2242 __ bind(&next);
2243 }
2244 Handle<Map> map = instr->hydrogen()->types()->last();
2245 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2246 if (instr->hydrogen()->need_generic()) {
2247 NearLabel generic;
2248 __ j(not_equal, &generic);
2249 EmitLoadField(result, object, map, name);
2250 __ jmp(&done);
2251 __ bind(&generic);
2252 __ mov(ecx, name);
2253 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002254 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002255 } else {
2256 DeoptimizeIf(not_equal, instr->environment());
2257 EmitLoadField(result, object, map, name);
2258 }
2259 __ bind(&done);
2260 }
2261}
2262
2263
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002264void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002265 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266 ASSERT(ToRegister(instr->object()).is(eax));
2267 ASSERT(ToRegister(instr->result()).is(eax));
2268
2269 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002270 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002271 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002272}
2273
2274
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002275void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2276 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002277 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002278 Register result = ToRegister(instr->result());
2279
2280 // Check that the function really is a function.
2281 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2282 DeoptimizeIf(not_equal, instr->environment());
2283
2284 // Check whether the function has an instance prototype.
2285 NearLabel non_instance;
2286 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2287 1 << Map::kHasNonInstancePrototype);
2288 __ j(not_zero, &non_instance);
2289
2290 // Get the prototype or initial map from the function.
2291 __ mov(result,
2292 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2293
2294 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002295 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002296 DeoptimizeIf(equal, instr->environment());
2297
2298 // If the function does not have an initial map, we're done.
2299 NearLabel done;
2300 __ CmpObjectType(result, MAP_TYPE, temp);
2301 __ j(not_equal, &done);
2302
2303 // Get the prototype from the initial map.
2304 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
2305 __ jmp(&done);
2306
2307 // Non-instance prototype: Fetch prototype from constructor field
2308 // in the function's map.
2309 __ bind(&non_instance);
2310 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2311
2312 // All done.
2313 __ bind(&done);
2314}
2315
2316
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002317void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002318 Register result = ToRegister(instr->result());
2319 Register input = ToRegister(instr->InputAt(0));
2320 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002321 if (FLAG_debug_code) {
2322 NearLabel done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002323 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002324 Immediate(factory()->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002325 __ j(equal, &done);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002326 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002327 Immediate(factory()->fixed_cow_array_map()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002328 __ j(equal, &done);
2329 Register temp((result.is(eax)) ? ebx : eax);
2330 __ push(temp);
2331 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
2332 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
2333 __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
2334 __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
2335 __ pop(temp);
2336 __ Check(below, "Check for fast elements or pixel array failed.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002337 __ bind(&done);
2338 }
2339}
2340
2341
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002342void LCodeGen::DoLoadExternalArrayPointer(
2343 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002344 Register result = ToRegister(instr->result());
2345 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002346 __ mov(result, FieldOperand(input,
2347 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002348}
2349
2350
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002351void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2352 Register arguments = ToRegister(instr->arguments());
2353 Register length = ToRegister(instr->length());
2354 Operand index = ToOperand(instr->index());
2355 Register result = ToRegister(instr->result());
2356
2357 __ sub(length, index);
2358 DeoptimizeIf(below_equal, instr->environment());
2359
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002360 // There are two words between the frame pointer and the last argument.
2361 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002362 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2363}
2364
2365
2366void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
2367 Register elements = ToRegister(instr->elements());
2368 Register key = ToRegister(instr->key());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002369 Register result = ToRegister(instr->result());
2370 ASSERT(result.is(elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002371
2372 // Load the result.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002373 __ mov(result, FieldOperand(elements,
2374 key,
2375 times_pointer_size,
2376 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002377
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002378 // Check for the hole value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002379 __ cmp(result, factory()->the_hole_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002380 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002381}
2382
2383
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002384void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2385 LLoadKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002386 Register external_pointer = ToRegister(instr->external_pointer());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002387 Register key = ToRegister(instr->key());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002388 ExternalArrayType array_type = instr->array_type();
2389 if (array_type == kExternalFloatArray) {
2390 XMMRegister result(ToDoubleRegister(instr->result()));
2391 __ movss(result, Operand(external_pointer, key, times_4, 0));
2392 __ cvtss2sd(result, result);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002393 } else if (array_type == kExternalDoubleArray) {
2394 __ movdbl(ToDoubleRegister(instr->result()),
2395 Operand(external_pointer, key, times_8, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002396 } else {
2397 Register result(ToRegister(instr->result()));
2398 switch (array_type) {
2399 case kExternalByteArray:
2400 __ movsx_b(result, Operand(external_pointer, key, times_1, 0));
2401 break;
2402 case kExternalUnsignedByteArray:
2403 case kExternalPixelArray:
2404 __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
2405 break;
2406 case kExternalShortArray:
2407 __ movsx_w(result, Operand(external_pointer, key, times_2, 0));
2408 break;
2409 case kExternalUnsignedShortArray:
2410 __ movzx_w(result, Operand(external_pointer, key, times_2, 0));
2411 break;
2412 case kExternalIntArray:
2413 __ mov(result, Operand(external_pointer, key, times_4, 0));
2414 break;
2415 case kExternalUnsignedIntArray:
2416 __ mov(result, Operand(external_pointer, key, times_4, 0));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002417 __ test(result, Operand(result));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002418 // TODO(danno): we could be more clever here, perhaps having a special
2419 // version of the stub that detects if the overflow case actually
2420 // happens, and generate code that returns a double rather than int.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002421 DeoptimizeIf(negative, instr->environment());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002422 break;
2423 case kExternalFloatArray:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002424 case kExternalDoubleArray:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002425 UNREACHABLE();
2426 break;
2427 }
2428 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002429}
2430
2431
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002432void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002433 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002434 ASSERT(ToRegister(instr->object()).is(edx));
2435 ASSERT(ToRegister(instr->key()).is(eax));
2436
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002437 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002438 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002439}
2440
2441
2442void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2443 Register result = ToRegister(instr->result());
2444
2445 // Check for arguments adapter frame.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002446 NearLabel done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002447 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2448 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2449 __ cmp(Operand(result),
2450 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2451 __ j(equal, &adapted);
2452
2453 // No arguments adaptor frame.
2454 __ mov(result, Operand(ebp));
2455 __ jmp(&done);
2456
2457 // Arguments adaptor frame present.
2458 __ bind(&adapted);
2459 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2460
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002461 // Result is the frame pointer for the frame if not adapted and for the real
2462 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002463 __ bind(&done);
2464}
2465
2466
2467void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002468 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002469 Register result = ToRegister(instr->result());
2470
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002471 NearLabel done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002472
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002473 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002474 __ cmp(ebp, elem);
2475 __ mov(result, Immediate(scope()->num_parameters()));
2476 __ j(equal, &done);
2477
2478 // Arguments adaptor frame present. Get argument length from there.
2479 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2480 __ mov(result, Operand(result,
2481 ArgumentsAdaptorFrameConstants::kLengthOffset));
2482 __ SmiUntag(result);
2483
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002484 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002485 __ bind(&done);
2486}
2487
2488
2489void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2490 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002491 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 Register length = ToRegister(instr->length());
2493 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002494 Register scratch = ToRegister(instr->TempAt(0));
2495 ASSERT(receiver.is(eax)); // Used for parameter count.
2496 ASSERT(function.is(edi)); // Required by InvokeFunction.
2497 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002498
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002499 // If the receiver is null or undefined, we have to pass the global object
2500 // as a receiver.
2501 NearLabel global_object, receiver_ok;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002502 __ cmp(receiver, factory()->null_value());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002503 __ j(equal, &global_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002504 __ cmp(receiver, factory()->undefined_value());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002505 __ j(equal, &global_object);
2506
2507 // The receiver should be a JS object.
2508 __ test(receiver, Immediate(kSmiTagMask));
2509 DeoptimizeIf(equal, instr->environment());
2510 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch);
2511 DeoptimizeIf(below, instr->environment());
2512 __ jmp(&receiver_ok);
2513
2514 __ bind(&global_object);
2515 // TODO(kmillikin): We have a hydrogen value for the global object. See
2516 // if it's better to use it than to explicitly fetch it from the context
2517 // here.
2518 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2519 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
2520 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002521
2522 // Copy the arguments to this function possibly from the
2523 // adaptor frame below it.
2524 const uint32_t kArgumentsLimit = 1 * KB;
2525 __ cmp(length, kArgumentsLimit);
2526 DeoptimizeIf(above, instr->environment());
2527
2528 __ push(receiver);
2529 __ mov(receiver, length);
2530
2531 // Loop through the arguments pushing them onto the execution
2532 // stack.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002533 NearLabel invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002534 // length is a small non-negative integer, due to the test above.
2535 __ test(length, Operand(length));
2536 __ j(zero, &invoke);
2537 __ bind(&loop);
2538 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2539 __ dec(length);
2540 __ j(not_zero, &loop);
2541
2542 // Invoke the function.
2543 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002544 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2545 LPointerMap* pointers = instr->pointer_map();
2546 LEnvironment* env = instr->deoptimization_environment();
2547 RecordPosition(pointers->position());
2548 RegisterEnvironmentForDeoptimization(env);
2549 SafepointGenerator safepoint_generator(this,
2550 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002551 env->deoptimization_index());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002552 ParameterCount actual(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002553 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002554}
2555
2556
2557void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002558 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002559 if (argument->IsConstantOperand()) {
2560 __ push(ToImmediate(argument));
2561 } else {
2562 __ push(ToOperand(argument));
2563 }
2564}
2565
2566
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002567void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002568 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002569 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002570}
2571
2572
2573void LCodeGen::DoOuterContext(LOuterContext* instr) {
2574 Register context = ToRegister(instr->context());
2575 Register result = ToRegister(instr->result());
2576 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2577 __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
2578}
2579
2580
2581void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2582 Register context = ToRegister(instr->context());
2583 Register result = ToRegister(instr->result());
2584 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002585}
2586
2587
2588void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002589 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002590 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002591 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002592}
2593
2594
2595void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2596 int arity,
2597 LInstruction* instr) {
2598 // Change context if needed.
2599 bool change_context =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002600 (info()->closure()->context() != function->context()) ||
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002601 scope()->contains_with() ||
2602 (scope()->num_heap_slots() > 0);
2603 if (change_context) {
2604 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002605 } else {
2606 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002607 }
2608
2609 // Set eax to arguments count if adaption is not needed. Assumes that eax
2610 // is available to write to at this point.
2611 if (!function->NeedsArgumentsAdaption()) {
2612 __ mov(eax, arity);
2613 }
2614
2615 LPointerMap* pointers = instr->pointer_map();
2616 RecordPosition(pointers->position());
2617
2618 // Invoke function.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002619 if (*function == *info()->closure()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002620 __ CallSelf();
2621 } else {
2622 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2623 }
2624
2625 // Setup deoptimization.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002626 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002627}
2628
2629
2630void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2631 ASSERT(ToRegister(instr->result()).is(eax));
2632 __ mov(edi, instr->function());
2633 CallKnownFunction(instr->function(), instr->arity(), instr);
2634}
2635
2636
2637void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002638 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002639 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002640 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002641 DeoptimizeIf(not_equal, instr->environment());
2642
2643 Label done;
2644 Register tmp = input_reg.is(eax) ? ecx : eax;
2645 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2646
2647 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002648 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002649
2650 Label negative;
2651 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002652 // Check the sign of the argument. If the argument is positive, just
2653 // return it. We do not need to patch the stack since |input| and
2654 // |result| are the same register and |input| will be restored
2655 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002656 __ test(tmp, Immediate(HeapNumber::kSignMask));
2657 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002658 __ jmp(&done);
2659
2660 __ bind(&negative);
2661
2662 Label allocated, slow;
2663 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2664 __ jmp(&allocated);
2665
2666 // Slow case: Call the runtime system to do the number allocation.
2667 __ bind(&slow);
2668
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002669 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
2670
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002671 // Set the pointer to the new heap number in tmp.
2672 if (!tmp.is(eax)) __ mov(tmp, eax);
2673
2674 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002675 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002676
2677 __ bind(&allocated);
2678 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2679 __ and_(tmp2, ~HeapNumber::kSignMask);
2680 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2681 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2682 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002683 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002684
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002685 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002686}
2687
2688
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002689void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2690 Register input_reg = ToRegister(instr->InputAt(0));
2691 __ test(input_reg, Operand(input_reg));
2692 Label is_positive;
2693 __ j(not_sign, &is_positive);
2694 __ neg(input_reg);
2695 __ test(input_reg, Operand(input_reg));
2696 DeoptimizeIf(negative, instr->environment());
2697 __ bind(&is_positive);
2698}
2699
2700
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002701void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2702 // Class for deferred case.
2703 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2704 public:
2705 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2706 LUnaryMathOperation* instr)
2707 : LDeferredCode(codegen), instr_(instr) { }
2708 virtual void Generate() {
2709 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2710 }
2711 private:
2712 LUnaryMathOperation* instr_;
2713 };
2714
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002715 ASSERT(instr->InputAt(0)->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002716 Representation r = instr->hydrogen()->value()->representation();
2717
2718 if (r.IsDouble()) {
2719 XMMRegister scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002720 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002721 __ pxor(scratch, scratch);
2722 __ subsd(scratch, input_reg);
2723 __ pand(input_reg, scratch);
2724 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002725 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002726 } else { // Tagged case.
2727 DeferredMathAbsTaggedHeapNumber* deferred =
2728 new DeferredMathAbsTaggedHeapNumber(this, instr);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002729 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002730 // Smi check.
2731 __ test(input_reg, Immediate(kSmiTagMask));
2732 __ j(not_zero, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002733 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002734 __ bind(deferred->exit());
2735 }
2736}
2737
2738
2739void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2740 XMMRegister xmm_scratch = xmm0;
2741 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002742 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002743 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2744 __ ucomisd(input_reg, xmm_scratch);
2745
2746 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2747 DeoptimizeIf(below_equal, instr->environment());
2748 } else {
2749 DeoptimizeIf(below, instr->environment());
2750 }
2751
2752 // Use truncating instruction (OK because input is positive).
2753 __ cvttsd2si(output_reg, Operand(input_reg));
2754
2755 // Overflow is signalled with minint.
2756 __ cmp(output_reg, 0x80000000u);
2757 DeoptimizeIf(equal, instr->environment());
2758}
2759
2760
2761void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2762 XMMRegister xmm_scratch = xmm0;
2763 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002764 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002765
danno@chromium.org160a7b02011-04-18 15:51:38 +00002766 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002767 // xmm_scratch = 0.5
2768 ExternalReference one_half = ExternalReference::address_of_one_half();
2769 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
2770
danno@chromium.org160a7b02011-04-18 15:51:38 +00002771 __ ucomisd(xmm_scratch, input_reg);
2772 __ j(above, &below_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002773 // input = input + 0.5
2774 __ addsd(input_reg, xmm_scratch);
2775
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002776
2777 // Compute Math.floor(value + 0.5).
2778 // Use truncating instruction (OK because input is positive).
2779 __ cvttsd2si(output_reg, Operand(input_reg));
2780
2781 // Overflow is signalled with minint.
2782 __ cmp(output_reg, 0x80000000u);
2783 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002784 __ jmp(&done);
2785
2786 __ bind(&below_half);
2787
2788 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
2789 // we can ignore the difference between a result of -0 and +0.
2790 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2791 // If the sign is positive, we return +0.
2792 __ movmskpd(output_reg, input_reg);
2793 __ test(output_reg, Immediate(1));
2794 DeoptimizeIf(not_zero, instr->environment());
2795 } else {
2796 // If the input is >= -0.5, we return +0.
2797 __ mov(output_reg, Immediate(0xBF000000));
2798 __ movd(xmm_scratch, Operand(output_reg));
2799 __ cvtss2sd(xmm_scratch, xmm_scratch);
2800 __ ucomisd(input_reg, xmm_scratch);
2801 DeoptimizeIf(below, instr->environment());
2802 }
2803 __ Set(output_reg, Immediate(0));
2804 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002805}
2806
2807
2808void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002809 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002810 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2811 __ sqrtsd(input_reg, input_reg);
2812}
2813
2814
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002815void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2816 XMMRegister xmm_scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002817 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002818 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002819 __ xorpd(xmm_scratch, xmm_scratch);
2820 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002821 __ sqrtsd(input_reg, input_reg);
2822}
2823
2824
2825void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002826 LOperand* left = instr->InputAt(0);
2827 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002828 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2829 Representation exponent_type = instr->hydrogen()->right()->representation();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002830
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002831 if (exponent_type.IsDouble()) {
2832 // It is safe to use ebx directly since the instruction is marked
2833 // as a call.
2834 __ PrepareCallCFunction(4, ebx);
2835 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2836 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002837 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2838 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002839 } else if (exponent_type.IsInteger32()) {
2840 // It is safe to use ebx directly since the instruction is marked
2841 // as a call.
2842 ASSERT(!ToRegister(right).is(ebx));
2843 __ PrepareCallCFunction(4, ebx);
2844 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2845 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
2847 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002848 } else {
2849 ASSERT(exponent_type.IsTagged());
2850 CpuFeatures::Scope scope(SSE2);
2851 Register right_reg = ToRegister(right);
2852
2853 Label non_smi, call;
2854 __ test(right_reg, Immediate(kSmiTagMask));
2855 __ j(not_zero, &non_smi);
2856 __ SmiUntag(right_reg);
2857 __ cvtsi2sd(result_reg, Operand(right_reg));
2858 __ jmp(&call);
2859
2860 __ bind(&non_smi);
2861 // It is safe to use ebx directly since the instruction is marked
2862 // as a call.
2863 ASSERT(!right_reg.is(ebx));
2864 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
2865 DeoptimizeIf(not_equal, instr->environment());
2866 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
2867
2868 __ bind(&call);
2869 __ PrepareCallCFunction(4, ebx);
2870 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2871 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002872 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2873 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002874 }
2875
2876 // Return value is in st(0) on ia32.
2877 // Store it into the (fixed) result register.
2878 __ sub(Operand(esp), Immediate(kDoubleSize));
2879 __ fstp_d(Operand(esp, 0));
2880 __ movdbl(result_reg, Operand(esp, 0));
2881 __ add(Operand(esp), Immediate(kDoubleSize));
2882}
2883
2884
2885void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002886 ASSERT(instr->InputAt(0)->Equals(instr->result()));
2887 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
2888 NearLabel positive, done, zero, negative;
2889 __ xorpd(xmm0, xmm0);
2890 __ ucomisd(input_reg, xmm0);
2891 __ j(above, &positive);
2892 __ j(equal, &zero);
2893 ExternalReference nan = ExternalReference::address_of_nan();
2894 __ movdbl(input_reg, Operand::StaticVariable(nan));
2895 __ jmp(&done);
2896 __ bind(&zero);
2897 __ push(Immediate(0xFFF00000));
2898 __ push(Immediate(0));
2899 __ movdbl(input_reg, Operand(esp, 0));
2900 __ add(Operand(esp), Immediate(kDoubleSize));
2901 __ jmp(&done);
2902 __ bind(&positive);
2903 __ fldln2();
2904 __ sub(Operand(esp), Immediate(kDoubleSize));
2905 __ movdbl(Operand(esp, 0), input_reg);
2906 __ fld_d(Operand(esp, 0));
2907 __ fyl2x();
2908 __ fstp_d(Operand(esp, 0));
2909 __ movdbl(input_reg, Operand(esp, 0));
2910 __ add(Operand(esp), Immediate(kDoubleSize));
2911 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002912}
2913
2914
2915void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
2916 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2917 TranscendentalCacheStub stub(TranscendentalCache::COS,
2918 TranscendentalCacheStub::UNTAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002919 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002920}
2921
2922
2923void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
2924 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2925 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2926 TranscendentalCacheStub::UNTAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002927 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002928}
2929
2930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002931void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
2932 switch (instr->op()) {
2933 case kMathAbs:
2934 DoMathAbs(instr);
2935 break;
2936 case kMathFloor:
2937 DoMathFloor(instr);
2938 break;
2939 case kMathRound:
2940 DoMathRound(instr);
2941 break;
2942 case kMathSqrt:
2943 DoMathSqrt(instr);
2944 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002945 case kMathPowHalf:
2946 DoMathPowHalf(instr);
2947 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00002948 case kMathCos:
2949 DoMathCos(instr);
2950 break;
2951 case kMathSin:
2952 DoMathSin(instr);
2953 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002954 case kMathLog:
2955 DoMathLog(instr);
2956 break;
2957
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002958 default:
2959 UNREACHABLE();
2960 }
2961}
2962
2963
danno@chromium.org160a7b02011-04-18 15:51:38 +00002964void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
2965 ASSERT(ToRegister(instr->context()).is(esi));
2966 ASSERT(ToRegister(instr->function()).is(edi));
2967 ASSERT(instr->HasPointerMap());
2968 ASSERT(instr->HasDeoptimizationEnvironment());
2969 LPointerMap* pointers = instr->pointer_map();
2970 LEnvironment* env = instr->deoptimization_environment();
2971 RecordPosition(pointers->position());
2972 RegisterEnvironmentForDeoptimization(env);
2973 SafepointGenerator generator(this, pointers, env->deoptimization_index());
2974 ParameterCount count(instr->arity());
2975 __ InvokeFunction(edi, count, CALL_FUNCTION, &generator);
2976}
2977
2978
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002979void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002980 ASSERT(ToRegister(instr->context()).is(esi));
2981 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002982 ASSERT(ToRegister(instr->result()).is(eax));
2983
2984 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002985 Handle<Code> ic = isolate()->stub_cache()->
2986 ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002987 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002988}
2989
2990
2991void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002992 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002993 ASSERT(ToRegister(instr->result()).is(eax));
2994
2995 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002996 Handle<Code> ic = isolate()->stub_cache()->
2997 ComputeCallInitialize(arity, NOT_IN_LOOP);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002998 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002999 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003000}
3001
3002
3003void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003004 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003005 ASSERT(ToRegister(instr->result()).is(eax));
3006
3007 int arity = instr->arity();
3008 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003009 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003010 __ Drop(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003011}
3012
3013
3014void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003015 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003016 ASSERT(ToRegister(instr->result()).is(eax));
3017
3018 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 Handle<Code> ic = isolate()->stub_cache()->
3020 ComputeCallInitialize(arity, NOT_IN_LOOP);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003021 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003022 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003023}
3024
3025
3026void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3027 ASSERT(ToRegister(instr->result()).is(eax));
3028 __ mov(edi, instr->target());
3029 CallKnownFunction(instr->target(), instr->arity(), instr);
3030}
3031
3032
3033void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003034 ASSERT(ToRegister(instr->context()).is(esi));
3035 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003036 ASSERT(ToRegister(instr->result()).is(eax));
3037
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003038 Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003039 __ Set(eax, Immediate(instr->arity()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003040 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003041}
3042
3043
3044void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003045 CallRuntime(instr->function(), instr->arity(), instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003046}
3047
3048
3049void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3050 Register object = ToRegister(instr->object());
3051 Register value = ToRegister(instr->value());
3052 int offset = instr->offset();
3053
3054 if (!instr->transition().is_null()) {
3055 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3056 }
3057
3058 // Do the store.
3059 if (instr->is_in_object()) {
3060 __ mov(FieldOperand(object, offset), value);
3061 if (instr->needs_write_barrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003062 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003063 // Update the write barrier for the object for in-object properties.
3064 __ RecordWrite(object, offset, value, temp);
3065 }
3066 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003067 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003068 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3069 __ mov(FieldOperand(temp, offset), value);
3070 if (instr->needs_write_barrier()) {
3071 // Update the write barrier for the properties array.
3072 // object is used as a scratch register.
3073 __ RecordWrite(temp, offset, value, object);
3074 }
3075 }
3076}
3077
3078
3079void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003080 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003081 ASSERT(ToRegister(instr->object()).is(edx));
3082 ASSERT(ToRegister(instr->value()).is(eax));
3083
3084 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003085 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003086 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3087 : isolate()->builtins()->StoreIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003088 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003089}
3090
3091
3092void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
3093 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3094 DeoptimizeIf(above_equal, instr->environment());
3095}
3096
3097
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003098void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3099 LStoreKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003100 Register external_pointer = ToRegister(instr->external_pointer());
3101 Register key = ToRegister(instr->key());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003102 ExternalArrayType array_type = instr->array_type();
3103 if (array_type == kExternalFloatArray) {
3104 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
3105 __ movss(Operand(external_pointer, key, times_4, 0), xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003106 } else if (array_type == kExternalDoubleArray) {
3107 __ movdbl(Operand(external_pointer, key, times_8, 0),
3108 ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003109 } else {
3110 Register value = ToRegister(instr->value());
3111 switch (array_type) {
3112 case kExternalPixelArray: {
3113 // Clamp the value to [0..255].
3114 Register temp = ToRegister(instr->TempAt(0));
3115 // The dec_b below requires that the clamped value is in a byte
3116 // register. eax is an arbitrary choice to satisfy this requirement, we
3117 // hinted the register allocator to give us eax when building the
3118 // instruction.
3119 ASSERT(temp.is(eax));
3120 __ mov(temp, ToRegister(instr->value()));
3121 NearLabel done;
3122 __ test(temp, Immediate(0xFFFFFF00));
3123 __ j(zero, &done);
3124 __ setcc(negative, temp); // 1 if negative, 0 if positive.
3125 __ dec_b(temp); // 0 if negative, 255 if positive.
3126 __ bind(&done);
3127 __ mov_b(Operand(external_pointer, key, times_1, 0), temp);
3128 break;
3129 }
3130 case kExternalByteArray:
3131 case kExternalUnsignedByteArray:
3132 __ mov_b(Operand(external_pointer, key, times_1, 0), value);
3133 break;
3134 case kExternalShortArray:
3135 case kExternalUnsignedShortArray:
3136 __ mov_w(Operand(external_pointer, key, times_2, 0), value);
3137 break;
3138 case kExternalIntArray:
3139 case kExternalUnsignedIntArray:
3140 __ mov(Operand(external_pointer, key, times_4, 0), value);
3141 break;
3142 case kExternalFloatArray:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003143 case kExternalDoubleArray:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003144 UNREACHABLE();
3145 break;
3146 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003147 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003148}
3149
3150
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003151void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3152 Register value = ToRegister(instr->value());
3153 Register elements = ToRegister(instr->object());
3154 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3155
3156 // Do the store.
3157 if (instr->key()->IsConstantOperand()) {
3158 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3159 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3160 int offset =
3161 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3162 __ mov(FieldOperand(elements, offset), value);
3163 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003164 __ mov(FieldOperand(elements,
3165 key,
3166 times_pointer_size,
3167 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003168 value);
3169 }
3170
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003171 if (instr->hydrogen()->NeedsWriteBarrier()) {
3172 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003173 __ lea(key,
3174 FieldOperand(elements,
3175 key,
3176 times_pointer_size,
3177 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003178 __ RecordWrite(elements, key, value);
3179 }
3180}
3181
3182
3183void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003184 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003185 ASSERT(ToRegister(instr->object()).is(edx));
3186 ASSERT(ToRegister(instr->key()).is(ecx));
3187 ASSERT(ToRegister(instr->value()).is(eax));
3188
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003189 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003190 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3191 : isolate()->builtins()->KeyedStoreIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003192 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003193}
3194
3195
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003196void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3197 class DeferredStringCharCodeAt: public LDeferredCode {
3198 public:
3199 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3200 : LDeferredCode(codegen), instr_(instr) { }
3201 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
3202 private:
3203 LStringCharCodeAt* instr_;
3204 };
3205
3206 Register string = ToRegister(instr->string());
3207 Register index = no_reg;
3208 int const_index = -1;
3209 if (instr->index()->IsConstantOperand()) {
3210 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3211 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3212 if (!Smi::IsValid(const_index)) {
3213 // Guaranteed to be out of bounds because of the assert above.
3214 // So the bounds check that must dominate this instruction must
3215 // have deoptimized already.
3216 if (FLAG_debug_code) {
3217 __ Abort("StringCharCodeAt: out of bounds index.");
3218 }
3219 // No code needs to be generated.
3220 return;
3221 }
3222 } else {
3223 index = ToRegister(instr->index());
3224 }
3225 Register result = ToRegister(instr->result());
3226
3227 DeferredStringCharCodeAt* deferred =
3228 new DeferredStringCharCodeAt(this, instr);
3229
3230 NearLabel flat_string, ascii_string, done;
3231
3232 // Fetch the instance type of the receiver into result register.
3233 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3234 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3235
3236 // We need special handling for non-flat strings.
3237 STATIC_ASSERT(kSeqStringTag == 0);
3238 __ test(result, Immediate(kStringRepresentationMask));
3239 __ j(zero, &flat_string);
3240
3241 // Handle non-flat strings.
3242 __ test(result, Immediate(kIsConsStringMask));
3243 __ j(zero, deferred->entry());
3244
3245 // ConsString.
3246 // Check whether the right hand side is the empty string (i.e. if
3247 // this is really a flat string in a cons string). If that is not
3248 // the case we would rather go to the runtime system now to flatten
3249 // the string.
3250 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003251 Immediate(factory()->empty_string()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003252 __ j(not_equal, deferred->entry());
3253 // Get the first of the two strings and load its instance type.
3254 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
3255 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3256 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3257 // If the first cons component is also non-flat, then go to runtime.
3258 STATIC_ASSERT(kSeqStringTag == 0);
3259 __ test(result, Immediate(kStringRepresentationMask));
3260 __ j(not_zero, deferred->entry());
3261
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003262 // Check for ASCII or two-byte string.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003263 __ bind(&flat_string);
3264 STATIC_ASSERT(kAsciiStringTag != 0);
3265 __ test(result, Immediate(kStringEncodingMask));
3266 __ j(not_zero, &ascii_string);
3267
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003268 // Two-byte string.
3269 // Load the two-byte character code into the result register.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003270 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3271 if (instr->index()->IsConstantOperand()) {
3272 __ movzx_w(result,
3273 FieldOperand(string,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003274 SeqTwoByteString::kHeaderSize +
3275 (kUC16Size * const_index)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003276 } else {
3277 __ movzx_w(result, FieldOperand(string,
3278 index,
3279 times_2,
3280 SeqTwoByteString::kHeaderSize));
3281 }
3282 __ jmp(&done);
3283
3284 // ASCII string.
3285 // Load the byte into the result register.
3286 __ bind(&ascii_string);
3287 if (instr->index()->IsConstantOperand()) {
3288 __ movzx_b(result, FieldOperand(string,
3289 SeqAsciiString::kHeaderSize + const_index));
3290 } else {
3291 __ movzx_b(result, FieldOperand(string,
3292 index,
3293 times_1,
3294 SeqAsciiString::kHeaderSize));
3295 }
3296 __ bind(&done);
3297 __ bind(deferred->exit());
3298}
3299
3300
3301void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3302 Register string = ToRegister(instr->string());
3303 Register result = ToRegister(instr->result());
3304
3305 // TODO(3095996): Get rid of this. For now, we need to make the
3306 // result register contain a valid pointer because it is already
3307 // contained in the register pointer map.
3308 __ Set(result, Immediate(0));
3309
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003310 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003311 __ push(string);
3312 // Push the index as a smi. This is safe because of the checks in
3313 // DoStringCharCodeAt above.
3314 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3315 if (instr->index()->IsConstantOperand()) {
3316 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3317 __ push(Immediate(Smi::FromInt(const_index)));
3318 } else {
3319 Register index = ToRegister(instr->index());
3320 __ SmiTag(index);
3321 __ push(index);
3322 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003323 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003324 if (FLAG_debug_code) {
3325 __ AbortIfNotSmi(eax);
3326 }
3327 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003328 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003329}
3330
3331
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003332void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3333 class DeferredStringCharFromCode: public LDeferredCode {
3334 public:
3335 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3336 : LDeferredCode(codegen), instr_(instr) { }
3337 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
3338 private:
3339 LStringCharFromCode* instr_;
3340 };
3341
3342 DeferredStringCharFromCode* deferred =
3343 new DeferredStringCharFromCode(this, instr);
3344
3345 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3346 Register char_code = ToRegister(instr->char_code());
3347 Register result = ToRegister(instr->result());
3348 ASSERT(!char_code.is(result));
3349
3350 __ cmp(char_code, String::kMaxAsciiCharCode);
3351 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003353 __ mov(result, FieldOperand(result,
3354 char_code, times_pointer_size,
3355 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003356 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003357 __ j(equal, deferred->entry());
3358 __ bind(deferred->exit());
3359}
3360
3361
3362void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3363 Register char_code = ToRegister(instr->char_code());
3364 Register result = ToRegister(instr->result());
3365
3366 // TODO(3095996): Get rid of this. For now, we need to make the
3367 // result register contain a valid pointer because it is already
3368 // contained in the register pointer map.
3369 __ Set(result, Immediate(0));
3370
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003371 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003372 __ SmiTag(char_code);
3373 __ push(char_code);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003374 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003375 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003376}
3377
3378
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003379void LCodeGen::DoStringLength(LStringLength* instr) {
3380 Register string = ToRegister(instr->string());
3381 Register result = ToRegister(instr->result());
3382 __ mov(result, FieldOperand(string, String::kLengthOffset));
3383}
3384
3385
danno@chromium.org160a7b02011-04-18 15:51:38 +00003386void LCodeGen::DoStringAdd(LStringAdd* instr) {
3387 if (instr->left()->IsConstantOperand()) {
3388 __ push(ToImmediate(instr->left()));
3389 } else {
3390 __ push(ToOperand(instr->left()));
3391 }
3392 if (instr->right()->IsConstantOperand()) {
3393 __ push(ToImmediate(instr->right()));
3394 } else {
3395 __ push(ToOperand(instr->right()));
3396 }
3397 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
3398 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
3399}
3400
3401
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003402void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003403 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003404 ASSERT(input->IsRegister() || input->IsStackSlot());
3405 LOperand* output = instr->result();
3406 ASSERT(output->IsDoubleRegister());
3407 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3408}
3409
3410
3411void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3412 class DeferredNumberTagI: public LDeferredCode {
3413 public:
3414 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3415 : LDeferredCode(codegen), instr_(instr) { }
3416 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
3417 private:
3418 LNumberTagI* instr_;
3419 };
3420
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003421 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003422 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3423 Register reg = ToRegister(input);
3424
3425 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3426 __ SmiTag(reg);
3427 __ j(overflow, deferred->entry());
3428 __ bind(deferred->exit());
3429}
3430
3431
3432void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3433 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003434 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003435 Register tmp = reg.is(eax) ? ecx : eax;
3436
3437 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003438 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003439
3440 // There was overflow, so bits 30 and 31 of the original integer
3441 // disagree. Try to allocate a heap number in new space and store
3442 // the value in there. If that fails, call the runtime system.
3443 NearLabel done;
3444 __ SmiUntag(reg);
3445 __ xor_(reg, 0x80000000);
3446 __ cvtsi2sd(xmm0, Operand(reg));
3447 if (FLAG_inline_new) {
3448 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
3449 __ jmp(&done);
3450 }
3451
3452 // Slow case: Call the runtime system to do the number allocation.
3453 __ bind(&slow);
3454
3455 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3456 // register is stored, as this register is in the pointer map, but contains an
3457 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003458 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003459
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003460 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003461 if (!reg.is(eax)) __ mov(reg, eax);
3462
3463 // Done. Put the value in xmm0 into the value of the allocated heap
3464 // number.
3465 __ bind(&done);
3466 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003467 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003468}
3469
3470
3471void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3472 class DeferredNumberTagD: public LDeferredCode {
3473 public:
3474 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3475 : LDeferredCode(codegen), instr_(instr) { }
3476 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
3477 private:
3478 LNumberTagD* instr_;
3479 };
3480
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003481 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003482 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003483 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003484
3485 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3486 if (FLAG_inline_new) {
3487 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3488 } else {
3489 __ jmp(deferred->entry());
3490 }
3491 __ bind(deferred->exit());
3492 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3493}
3494
3495
3496void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3497 // TODO(3095996): Get rid of this. For now, we need to make the
3498 // result register contain a valid pointer because it is already
3499 // contained in the register pointer map.
3500 Register reg = ToRegister(instr->result());
3501 __ Set(reg, Immediate(0));
3502
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003503 PushSafepointRegistersScope scope(this);
3504 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003505 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003506}
3507
3508
3509void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003510 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003511 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3512 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3513 __ SmiTag(ToRegister(input));
3514}
3515
3516
3517void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003518 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003519 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3520 if (instr->needs_check()) {
3521 __ test(ToRegister(input), Immediate(kSmiTagMask));
3522 DeoptimizeIf(not_zero, instr->environment());
3523 }
3524 __ SmiUntag(ToRegister(input));
3525}
3526
3527
3528void LCodeGen::EmitNumberUntagD(Register input_reg,
3529 XMMRegister result_reg,
3530 LEnvironment* env) {
3531 NearLabel load_smi, heap_number, done;
3532
3533 // Smi check.
3534 __ test(input_reg, Immediate(kSmiTagMask));
3535 __ j(zero, &load_smi, not_taken);
3536
3537 // Heap number map check.
3538 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003540 __ j(equal, &heap_number);
3541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003543 DeoptimizeIf(not_equal, env);
3544
3545 // Convert undefined to NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 ExternalReference nan = ExternalReference::address_of_nan();
3547 __ movdbl(result_reg, Operand::StaticVariable(nan));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003548 __ jmp(&done);
3549
3550 // Heap number to XMM conversion.
3551 __ bind(&heap_number);
3552 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3553 __ jmp(&done);
3554
3555 // Smi to XMM conversion
3556 __ bind(&load_smi);
3557 __ SmiUntag(input_reg); // Untag smi before converting to float.
3558 __ cvtsi2sd(result_reg, Operand(input_reg));
3559 __ SmiTag(input_reg); // Retag smi.
3560 __ bind(&done);
3561}
3562
3563
3564class DeferredTaggedToI: public LDeferredCode {
3565 public:
3566 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3567 : LDeferredCode(codegen), instr_(instr) { }
3568 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3569 private:
3570 LTaggedToI* instr_;
3571};
3572
3573
3574void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
3575 NearLabel done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003576 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003577
3578 // Heap number map check.
3579 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003581
3582 if (instr->truncating()) {
3583 __ j(equal, &heap_number);
3584 // Check for undefined. Undefined is converted to zero for truncating
3585 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003587 DeoptimizeIf(not_equal, instr->environment());
3588 __ mov(input_reg, 0);
3589 __ jmp(&done);
3590
3591 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003592 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003593 CpuFeatures::Scope scope(SSE3);
3594 NearLabel convert;
3595 // Use more powerful conversion when sse3 is available.
3596 // Load x87 register with heap number.
3597 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3598 // Get exponent alone and check for too-big exponent.
3599 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3600 __ and_(input_reg, HeapNumber::kExponentMask);
3601 const uint32_t kTooBigExponent =
3602 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3603 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
3604 __ j(less, &convert);
3605 // Pop FPU stack before deoptimizing.
3606 __ ffree(0);
3607 __ fincstp();
3608 DeoptimizeIf(no_condition, instr->environment());
3609
3610 // Reserve space for 64 bit answer.
3611 __ bind(&convert);
3612 __ sub(Operand(esp), Immediate(kDoubleSize));
3613 // Do conversion, which cannot fail because we checked the exponent.
3614 __ fisttp_d(Operand(esp, 0));
3615 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3616 __ add(Operand(esp), Immediate(kDoubleSize));
3617 } else {
3618 NearLabel deopt;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003619 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003620 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3621 __ cvttsd2si(input_reg, Operand(xmm0));
3622 __ cmp(input_reg, 0x80000000u);
3623 __ j(not_equal, &done);
3624 // Check if the input was 0x8000000 (kMinInt).
3625 // If no, then we got an overflow and we deoptimize.
3626 ExternalReference min_int = ExternalReference::address_of_min_int();
3627 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3628 __ ucomisd(xmm_temp, xmm0);
3629 DeoptimizeIf(not_equal, instr->environment());
3630 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3631 }
3632 } else {
3633 // Deoptimize if we don't have a heap number.
3634 DeoptimizeIf(not_equal, instr->environment());
3635
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003636 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003637 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3638 __ cvttsd2si(input_reg, Operand(xmm0));
3639 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3640 __ ucomisd(xmm0, xmm_temp);
3641 DeoptimizeIf(not_equal, instr->environment());
3642 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3643 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3644 __ test(input_reg, Operand(input_reg));
3645 __ j(not_zero, &done);
3646 __ movmskpd(input_reg, xmm0);
3647 __ and_(input_reg, 1);
3648 DeoptimizeIf(not_zero, instr->environment());
3649 }
3650 }
3651 __ bind(&done);
3652}
3653
3654
3655void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003656 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003657 ASSERT(input->IsRegister());
3658 ASSERT(input->Equals(instr->result()));
3659
3660 Register input_reg = ToRegister(input);
3661
3662 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3663
3664 // Smi check.
3665 __ test(input_reg, Immediate(kSmiTagMask));
3666 __ j(not_zero, deferred->entry());
3667
3668 // Smi to int32 conversion
3669 __ SmiUntag(input_reg); // Untag smi.
3670
3671 __ bind(deferred->exit());
3672}
3673
3674
3675void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003676 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003677 ASSERT(input->IsRegister());
3678 LOperand* result = instr->result();
3679 ASSERT(result->IsDoubleRegister());
3680
3681 Register input_reg = ToRegister(input);
3682 XMMRegister result_reg = ToDoubleRegister(result);
3683
3684 EmitNumberUntagD(input_reg, result_reg, instr->environment());
3685}
3686
3687
3688void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003689 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003690 ASSERT(input->IsDoubleRegister());
3691 LOperand* result = instr->result();
3692 ASSERT(result->IsRegister());
3693
3694 XMMRegister input_reg = ToDoubleRegister(input);
3695 Register result_reg = ToRegister(result);
3696
3697 if (instr->truncating()) {
3698 // Performs a truncating conversion of a floating point number as used by
3699 // the JS bitwise operations.
3700 __ cvttsd2si(result_reg, Operand(input_reg));
3701 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003702 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003703 // This will deoptimize if the exponent of the input in out of range.
3704 CpuFeatures::Scope scope(SSE3);
3705 NearLabel convert, done;
3706 __ j(not_equal, &done);
3707 __ sub(Operand(esp), Immediate(kDoubleSize));
3708 __ movdbl(Operand(esp, 0), input_reg);
3709 // Get exponent alone and check for too-big exponent.
3710 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3711 __ and_(result_reg, HeapNumber::kExponentMask);
3712 const uint32_t kTooBigExponent =
3713 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3714 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
3715 __ j(less, &convert);
3716 __ add(Operand(esp), Immediate(kDoubleSize));
3717 DeoptimizeIf(no_condition, instr->environment());
3718 __ bind(&convert);
3719 // Do conversion, which cannot fail because we checked the exponent.
3720 __ fld_d(Operand(esp, 0));
3721 __ fisttp_d(Operand(esp, 0));
3722 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3723 __ add(Operand(esp), Immediate(kDoubleSize));
3724 __ bind(&done);
3725 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003726 NearLabel done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003727 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003728 XMMRegister xmm_scratch = xmm0;
3729
3730 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3731 // manual conversion.
3732 __ j(not_equal, &done);
3733
3734 // Get high 32 bits of the input in result_reg and temp_reg.
3735 __ pshufd(xmm_scratch, input_reg, 1);
3736 __ movd(Operand(temp_reg), xmm_scratch);
3737 __ mov(result_reg, temp_reg);
3738
3739 // Prepare negation mask in temp_reg.
3740 __ sar(temp_reg, kBitsPerInt - 1);
3741
3742 // Extract the exponent from result_reg and subtract adjusted
3743 // bias from it. The adjustment is selected in a way such that
3744 // when the difference is zero, the answer is in the low 32 bits
3745 // of the input, otherwise a shift has to be performed.
3746 __ shr(result_reg, HeapNumber::kExponentShift);
3747 __ and_(result_reg,
3748 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3749 __ sub(Operand(result_reg),
3750 Immediate(HeapNumber::kExponentBias +
3751 HeapNumber::kExponentBits +
3752 HeapNumber::kMantissaBits));
3753 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3754 // special exponents.
3755 DeoptimizeIf(greater, instr->environment());
3756
3757 // Zero out the sign and the exponent in the input (by shifting
3758 // it to the left) and restore the implicit mantissa bit,
3759 // i.e. convert the input to unsigned int64 shifted left by
3760 // kExponentBits.
3761 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3762 // Minus zero has the most significant bit set and the other
3763 // bits cleared.
3764 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3765 __ psllq(input_reg, HeapNumber::kExponentBits);
3766 __ por(input_reg, xmm_scratch);
3767
3768 // Get the amount to shift the input right in xmm_scratch.
3769 __ neg(result_reg);
3770 __ movd(xmm_scratch, Operand(result_reg));
3771
3772 // Shift the input right and extract low 32 bits.
3773 __ psrlq(input_reg, xmm_scratch);
3774 __ movd(Operand(result_reg), input_reg);
3775
3776 // Use the prepared mask in temp_reg to negate the result if necessary.
3777 __ xor_(result_reg, Operand(temp_reg));
3778 __ sub(result_reg, Operand(temp_reg));
3779 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003780 }
3781 } else {
3782 NearLabel done;
3783 __ cvttsd2si(result_reg, Operand(input_reg));
3784 __ cvtsi2sd(xmm0, Operand(result_reg));
3785 __ ucomisd(xmm0, input_reg);
3786 DeoptimizeIf(not_equal, instr->environment());
3787 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3788 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3789 // The integer converted back is equal to the original. We
3790 // only have to test if we got -0 as an input.
3791 __ test(result_reg, Operand(result_reg));
3792 __ j(not_zero, &done);
3793 __ movmskpd(result_reg, input_reg);
3794 // Bit 0 contains the sign of the double in input_reg.
3795 // If input was positive, we are ok and return 0, otherwise
3796 // deoptimize.
3797 __ and_(result_reg, 1);
3798 DeoptimizeIf(not_zero, instr->environment());
3799 }
3800 __ bind(&done);
3801 }
3802}
3803
3804
3805void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003806 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003807 __ test(ToRegister(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003808 DeoptimizeIf(not_zero, instr->environment());
3809}
3810
3811
3812void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
3813 LOperand* input = instr->InputAt(0);
3814 __ test(ToRegister(input), Immediate(kSmiTagMask));
3815 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003816}
3817
3818
3819void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003820 Register input = ToRegister(instr->InputAt(0));
3821 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003822 InstanceType first = instr->hydrogen()->first();
3823 InstanceType last = instr->hydrogen()->last();
3824
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003825 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003826
3827 // If there is only one type in the interval check for equality.
3828 if (first == last) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003829 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3830 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003831 DeoptimizeIf(not_equal, instr->environment());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003832 } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
3833 // String has a dedicated bit in instance type.
3834 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), kIsNotStringMask);
3835 DeoptimizeIf(not_zero, instr->environment());
3836 } else {
3837 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3838 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003839 DeoptimizeIf(below, instr->environment());
3840 // Omit check for the last type.
3841 if (last != LAST_TYPE) {
3842 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3843 static_cast<int8_t>(last));
3844 DeoptimizeIf(above, instr->environment());
3845 }
3846 }
3847}
3848
3849
3850void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003851 ASSERT(instr->InputAt(0)->IsRegister());
3852 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003853 __ cmp(reg, instr->hydrogen()->target());
3854 DeoptimizeIf(not_equal, instr->environment());
3855}
3856
3857
3858void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003859 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003860 ASSERT(input->IsRegister());
3861 Register reg = ToRegister(input);
3862 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3863 instr->hydrogen()->map());
3864 DeoptimizeIf(not_equal, instr->environment());
3865}
3866
3867
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003868void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869 if (isolate()->heap()->InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003871 isolate()->factory()->NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003872 __ mov(result, Operand::Cell(cell));
3873 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003874 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003875 }
3876}
3877
3878
3879void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003880 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003881
3882 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003883 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003884
3885 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003886 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003887
3888 // Check prototype maps up to the holder.
3889 while (!current_prototype.is_identical_to(holder)) {
3890 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3891 Handle<Map>(current_prototype->map()));
3892 DeoptimizeIf(not_equal, instr->environment());
3893 current_prototype =
3894 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3895 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003896 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897 }
3898
3899 // Check the holder map.
3900 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3901 Handle<Map>(current_prototype->map()));
3902 DeoptimizeIf(not_equal, instr->environment());
3903}
3904
3905
3906void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
3907 // Setup the parameters to the stub/runtime call.
3908 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3909 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3910 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3911 __ push(Immediate(instr->hydrogen()->constant_elements()));
3912
3913 // Pick the right runtime function or stub to call.
3914 int length = instr->hydrogen()->length();
3915 if (instr->hydrogen()->IsCopyOnWrite()) {
3916 ASSERT(instr->hydrogen()->depth() == 1);
3917 FastCloneShallowArrayStub::Mode mode =
3918 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
3919 FastCloneShallowArrayStub stub(mode, length);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003920 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003921 } else if (instr->hydrogen()->depth() > 1) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003922 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003923 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003924 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003925 } else {
3926 FastCloneShallowArrayStub::Mode mode =
3927 FastCloneShallowArrayStub::CLONE_ELEMENTS;
3928 FastCloneShallowArrayStub stub(mode, length);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003929 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003930 }
3931}
3932
3933
3934void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003935 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003936 // Setup the parameters to the stub/runtime call.
3937 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3938 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3939 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3940 __ push(Immediate(instr->hydrogen()->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003941 int flags = instr->hydrogen()->fast_elements()
3942 ? ObjectLiteral::kFastElements
3943 : ObjectLiteral::kNoFlags;
3944 flags |= instr->hydrogen()->has_function()
3945 ? ObjectLiteral::kHasFunction
3946 : ObjectLiteral::kNoFlags;
3947 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003948
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003949 // Pick the right runtime function to call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003950 if (instr->hydrogen()->depth() > 1) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003951 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003952 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003953 CallRuntime(Runtime::kCreateObjectLiteralShallow,
3954 4,
3955 instr,
3956 CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003957 }
3958}
3959
3960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003961void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
3962 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
3963 __ push(eax);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003964 CallRuntime(Runtime::kToFastProperties, 1, instr, CONTEXT_ADJUSTED);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003965}
3966
3967
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003968void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
3969 NearLabel materialized;
3970 // Registers will be used as follows:
3971 // edi = JS function.
3972 // ecx = literals array.
3973 // ebx = regexp literal.
3974 // eax = regexp literal clone.
3975 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3976 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
3977 int literal_offset = FixedArray::kHeaderSize +
3978 instr->hydrogen()->literal_index() * kPointerSize;
3979 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 __ cmp(ebx, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003981 __ j(not_equal, &materialized);
3982
3983 // Create regexp literal using runtime function
3984 // Result will be in eax.
3985 __ push(ecx);
3986 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3987 __ push(Immediate(instr->hydrogen()->pattern()));
3988 __ push(Immediate(instr->hydrogen()->flags()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003989 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003990 __ mov(ebx, eax);
3991
3992 __ bind(&materialized);
3993 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
3994 Label allocated, runtime_allocate;
3995 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
3996 __ jmp(&allocated);
3997
3998 __ bind(&runtime_allocate);
3999 __ push(ebx);
4000 __ push(Immediate(Smi::FromInt(size)));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004001 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004002 __ pop(ebx);
4003
4004 __ bind(&allocated);
4005 // Copy the content into the newly allocated memory.
4006 // (Unroll copy loop once for better throughput).
4007 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4008 __ mov(edx, FieldOperand(ebx, i));
4009 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
4010 __ mov(FieldOperand(eax, i), edx);
4011 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
4012 }
4013 if ((size % (2 * kPointerSize)) != 0) {
4014 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
4015 __ mov(FieldOperand(eax, size - kPointerSize), edx);
4016 }
4017}
4018
4019
4020void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
4021 // Use the fast case closure allocation code that allocates in new
4022 // space for nested functions that don't need literals cloning.
4023 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004024 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004025 if (!pretenure && shared_info->num_literals() == 0) {
4026 FastNewClosureStub stub(
4027 shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004028 __ push(Immediate(shared_info));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004029 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004030 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004031 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004032 __ push(Immediate(shared_info));
4033 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004034 ? factory()->true_value()
4035 : factory()->false_value()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004036 CallRuntime(Runtime::kNewClosure, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004037 }
4038}
4039
4040
4041void LCodeGen::DoTypeof(LTypeof* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004042 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004043 if (input->IsConstantOperand()) {
4044 __ push(ToImmediate(input));
4045 } else {
4046 __ push(ToOperand(input));
4047 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004048 CallRuntime(Runtime::kTypeof, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004049}
4050
4051
4052void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004053 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004054 Register result = ToRegister(instr->result());
4055 Label true_label;
4056 Label false_label;
4057 NearLabel done;
4058
4059 Condition final_branch_condition = EmitTypeofIs(&true_label,
4060 &false_label,
4061 input,
4062 instr->type_literal());
4063 __ j(final_branch_condition, &true_label);
4064 __ bind(&false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004065 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004066 __ jmp(&done);
4067
4068 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004069 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004070
4071 __ bind(&done);
4072}
4073
4074
4075void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004076 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004077 int true_block = chunk_->LookupDestination(instr->true_block_id());
4078 int false_block = chunk_->LookupDestination(instr->false_block_id());
4079 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4080 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4081
4082 Condition final_branch_condition = EmitTypeofIs(true_label,
4083 false_label,
4084 input,
4085 instr->type_literal());
4086
4087 EmitBranch(true_block, false_block, final_branch_condition);
4088}
4089
4090
4091Condition LCodeGen::EmitTypeofIs(Label* true_label,
4092 Label* false_label,
4093 Register input,
4094 Handle<String> type_name) {
4095 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004096 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004098 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004099 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004100 final_branch_condition = equal;
4101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004102 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 __ JumpIfSmi(input, false_label);
4104 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
4105 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004106 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4107 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004108 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004110 } else if (type_name->Equals(heap()->boolean_symbol())) {
4111 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004112 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004113 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004114 final_branch_condition = equal;
4115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004116 } else if (type_name->Equals(heap()->undefined_symbol())) {
4117 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004118 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004119 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004120 // Check for undetectable objects => true.
4121 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
4122 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4123 1 << Map::kIsUndetectable);
4124 final_branch_condition = not_zero;
4125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 } else if (type_name->Equals(heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004127 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004128 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
4129 __ j(equal, true_label);
4130 // Regular expressions => 'function' (they are callable).
4131 __ CmpInstanceType(input, JS_REGEXP_TYPE);
4132 final_branch_condition = equal;
4133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004135 __ JumpIfSmi(input, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004136 __ cmp(input, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004137 __ j(equal, true_label);
4138 // Regular expressions => 'function', not 'object'.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004139 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input);
4140 __ j(below, false_label);
4141 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
4142 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004143 // Check for undetectable objects => false.
4144 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4145 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004146 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004147
4148 } else {
4149 final_branch_condition = not_equal;
4150 __ jmp(false_label);
4151 // A dead branch instruction will be generated after this point.
4152 }
4153
4154 return final_branch_condition;
4155}
4156
4157
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004158void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
4159 Register result = ToRegister(instr->result());
4160 NearLabel true_label;
4161 NearLabel false_label;
4162 NearLabel done;
4163
4164 EmitIsConstructCall(result);
4165 __ j(equal, &true_label);
4166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004167 __ mov(result, factory()->false_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004168 __ jmp(&done);
4169
4170 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004171 __ mov(result, factory()->true_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004172
4173 __ bind(&done);
4174}
4175
4176
4177void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4178 Register temp = ToRegister(instr->TempAt(0));
4179 int true_block = chunk_->LookupDestination(instr->true_block_id());
4180 int false_block = chunk_->LookupDestination(instr->false_block_id());
4181
4182 EmitIsConstructCall(temp);
4183 EmitBranch(true_block, false_block, equal);
4184}
4185
4186
4187void LCodeGen::EmitIsConstructCall(Register temp) {
4188 // Get the frame pointer for the calling frame.
4189 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4190
4191 // Skip the arguments adaptor frame if it exists.
4192 NearLabel check_frame_marker;
4193 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4194 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4195 __ j(not_equal, &check_frame_marker);
4196 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
4197
4198 // Check the marker in the calling frame.
4199 __ bind(&check_frame_marker);
4200 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4201 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
4202}
4203
4204
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004205void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
4206 // No code for lazy bailout instruction. Used to capture environment after a
4207 // call for populating the safepoint data with deoptimization data.
4208}
4209
4210
4211void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4212 DeoptimizeIf(no_condition, instr->environment());
4213}
4214
4215
4216void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
4217 LOperand* obj = instr->object();
4218 LOperand* key = instr->key();
4219 __ push(ToOperand(obj));
4220 if (key->IsConstantOperand()) {
4221 __ push(ToImmediate(key));
4222 } else {
4223 __ push(ToOperand(key));
4224 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004225 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4226 LPointerMap* pointers = instr->pointer_map();
4227 LEnvironment* env = instr->deoptimization_environment();
4228 RecordPosition(pointers->position());
4229 RegisterEnvironmentForDeoptimization(env);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004230 // Create safepoint generator that will also ensure enough space in the
4231 // reloc info for patching in deoptimization (since this is invoking a
4232 // builtin)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004233 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004234 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004235 env->deoptimization_index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004236 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004237 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004238 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
4239}
4240
4241
4242void LCodeGen::DoStackCheck(LStackCheck* instr) {
4243 // Perform stack overflow check.
4244 NearLabel done;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004245 ExternalReference stack_limit =
4246 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004247 __ cmp(esp, Operand::StaticVariable(stack_limit));
4248 __ j(above_equal, &done);
4249
4250 StackCheckStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004251 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004252 __ bind(&done);
4253}
4254
4255
4256void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
4257 // This is a pseudo-instruction that ensures that the environment here is
4258 // properly registered for deoptimization and records the assembler's PC
4259 // offset.
4260 LEnvironment* environment = instr->environment();
4261 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4262 instr->SpilledDoubleRegisterArray());
4263
4264 // If the environment were already registered, we would have no way of
4265 // backpatching it with the spill slot operands.
4266 ASSERT(!environment->HasBeenRegistered());
4267 RegisterEnvironmentForDeoptimization(environment);
4268 ASSERT(osr_pc_offset_ == -1);
4269 osr_pc_offset_ = masm()->pc_offset();
4270}
4271
4272
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004273void LCodeGen::DoIn(LIn* instr) {
4274 LOperand* obj = instr->object();
4275 LOperand* key = instr->key();
4276 if (key->IsConstantOperand()) {
4277 __ push(ToImmediate(key));
4278 } else {
4279 __ push(ToOperand(key));
4280 }
4281 if (obj->IsConstantOperand()) {
4282 __ push(ToImmediate(obj));
4283 } else {
4284 __ push(ToOperand(obj));
4285 }
4286 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4287 LPointerMap* pointers = instr->pointer_map();
4288 LEnvironment* env = instr->deoptimization_environment();
4289 RecordPosition(pointers->position());
4290 RegisterEnvironmentForDeoptimization(env);
4291 // Create safepoint generator that will also ensure enough space in the
4292 // reloc info for patching in deoptimization (since this is invoking a
4293 // builtin)
4294 SafepointGenerator safepoint_generator(this,
4295 pointers,
4296 env->deoptimization_index());
4297 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4298 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, &safepoint_generator);
4299}
4300
4301
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004302#undef __
4303
4304} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004305
4306#endif // V8_TARGET_ARCH_IA32