blob: 7724f1b8208dead2365b2089165954d8be39785c [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"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000040// When invoking builtins, we need to record the safepoint in the middle of
41// the invoke instruction sequence generated by the macro assembler.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042class SafepointGenerator : public PostCallGenerator {
43 public:
44 SafepointGenerator(LCodeGen* codegen,
45 LPointerMap* pointers,
46 int deoptimization_index)
47 : codegen_(codegen),
48 pointers_(pointers),
49 deoptimization_index_(deoptimization_index) { }
50 virtual ~SafepointGenerator() { }
51
52 virtual void Generate() {
53 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
54 }
55
56 private:
57 LCodeGen* codegen_;
58 LPointerMap* pointers_;
59 int deoptimization_index_;
60};
61
62
63#define __ masm()->
64
65bool LCodeGen::GenerateCode() {
66 HPhase phase("Code generation", chunk());
67 ASSERT(is_unused());
68 status_ = GENERATING;
69 CpuFeatures::Scope scope(SSE2);
70 return GeneratePrologue() &&
71 GenerateBody() &&
72 GenerateDeferredCode() &&
73 GenerateSafepointTable();
74}
75
76
77void LCodeGen::FinishCode(Handle<Code> code) {
78 ASSERT(is_done());
79 code->set_stack_slots(StackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000080 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000081 PopulateDeoptimizationData(code);
82}
83
84
85void LCodeGen::Abort(const char* format, ...) {
86 if (FLAG_trace_bailout) {
87 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
88 PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
89 va_list arguments;
90 va_start(arguments, format);
91 OS::VPrint(format, arguments);
92 va_end(arguments);
93 PrintF("\n");
94 }
95 status_ = ABORTED;
96}
97
98
99void LCodeGen::Comment(const char* format, ...) {
100 if (!FLAG_code_comments) return;
101 char buffer[4 * KB];
102 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
103 va_list arguments;
104 va_start(arguments, format);
105 builder.AddFormattedList(format, arguments);
106 va_end(arguments);
107
108 // Copy the string before recording it in the assembler to avoid
109 // issues when the stack allocated buffer goes out of scope.
110 size_t length = builder.position();
111 Vector<char> copy = Vector<char>::New(length + 1);
112 memcpy(copy.start(), builder.Finalize(), copy.length());
113 masm()->RecordComment(copy.start());
114}
115
116
117bool LCodeGen::GeneratePrologue() {
118 ASSERT(is_generating());
119
120#ifdef DEBUG
121 if (strlen(FLAG_stop_at) > 0 &&
122 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
123 __ int3();
124 }
125#endif
126
127 __ push(ebp); // Caller's frame pointer.
128 __ mov(ebp, esp);
129 __ push(esi); // Callee's context.
130 __ push(edi); // Callee's JS function.
131
132 // Reserve space for the stack slots needed by the code.
133 int slots = StackSlotCount();
134 if (slots > 0) {
135 if (FLAG_debug_code) {
136 __ mov(Operand(eax), Immediate(slots));
137 Label loop;
138 __ bind(&loop);
139 __ push(Immediate(kSlotsZapValue));
140 __ dec(eax);
141 __ j(not_zero, &loop);
142 } else {
143 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000144#ifdef _MSC_VER
145 // On windows, you may not access the stack more than one page below
146 // the most recently mapped page. To make the allocated area randomly
147 // accessible, we write to each page in turn (the value is irrelevant).
148 const int kPageSize = 4 * KB;
149 for (int offset = slots * kPointerSize - kPageSize;
150 offset > 0;
151 offset -= kPageSize) {
152 __ mov(Operand(esp, offset), eax);
153 }
154#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000155 }
156 }
157
158 // Trace the call.
159 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000160 // We have not executed any compiled code yet, so esi still holds the
161 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000162 __ CallRuntime(Runtime::kTraceEnter, 0);
163 }
164 return !is_aborted();
165}
166
167
168bool LCodeGen::GenerateBody() {
169 ASSERT(is_generating());
170 bool emit_instructions = true;
171 for (current_instruction_ = 0;
172 !is_aborted() && current_instruction_ < instructions_->length();
173 current_instruction_++) {
174 LInstruction* instr = instructions_->at(current_instruction_);
175 if (instr->IsLabel()) {
176 LLabel* label = LLabel::cast(instr);
177 emit_instructions = !label->HasReplacement();
178 }
179
180 if (emit_instructions) {
181 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
182 instr->CompileToNative(this);
183 }
184 }
185 return !is_aborted();
186}
187
188
189LInstruction* LCodeGen::GetNextInstruction() {
190 if (current_instruction_ < instructions_->length() - 1) {
191 return instructions_->at(current_instruction_ + 1);
192 } else {
193 return NULL;
194 }
195}
196
197
198bool LCodeGen::GenerateDeferredCode() {
199 ASSERT(is_generating());
200 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
201 LDeferredCode* code = deferred_[i];
202 __ bind(code->entry());
203 code->Generate();
204 __ jmp(code->exit());
205 }
206
207 // Deferred code is the last part of the instruction sequence. Mark
208 // the generated code as done unless we bailed out.
209 if (!is_aborted()) status_ = DONE;
210 return !is_aborted();
211}
212
213
214bool LCodeGen::GenerateSafepointTable() {
215 ASSERT(is_done());
216 safepoints_.Emit(masm(), StackSlotCount());
217 return !is_aborted();
218}
219
220
221Register LCodeGen::ToRegister(int index) const {
222 return Register::FromAllocationIndex(index);
223}
224
225
226XMMRegister LCodeGen::ToDoubleRegister(int index) const {
227 return XMMRegister::FromAllocationIndex(index);
228}
229
230
231Register LCodeGen::ToRegister(LOperand* op) const {
232 ASSERT(op->IsRegister());
233 return ToRegister(op->index());
234}
235
236
237XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
238 ASSERT(op->IsDoubleRegister());
239 return ToDoubleRegister(op->index());
240}
241
242
243int LCodeGen::ToInteger32(LConstantOperand* op) const {
244 Handle<Object> value = chunk_->LookupLiteral(op);
245 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
246 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
247 value->Number());
248 return static_cast<int32_t>(value->Number());
249}
250
251
252Immediate LCodeGen::ToImmediate(LOperand* op) {
253 LConstantOperand* const_op = LConstantOperand::cast(op);
254 Handle<Object> literal = chunk_->LookupLiteral(const_op);
255 Representation r = chunk_->LookupLiteralRepresentation(const_op);
256 if (r.IsInteger32()) {
257 ASSERT(literal->IsNumber());
258 return Immediate(static_cast<int32_t>(literal->Number()));
259 } else if (r.IsDouble()) {
260 Abort("unsupported double immediate");
261 }
262 ASSERT(r.IsTagged());
263 return Immediate(literal);
264}
265
266
267Operand LCodeGen::ToOperand(LOperand* op) const {
268 if (op->IsRegister()) return Operand(ToRegister(op));
269 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
270 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
271 int index = op->index();
272 if (index >= 0) {
273 // Local or spill slot. Skip the frame pointer, function, and
274 // context in the fixed part of the frame.
275 return Operand(ebp, -(index + 3) * kPointerSize);
276 } else {
277 // Incoming parameter. Skip the return address.
278 return Operand(ebp, -(index - 1) * kPointerSize);
279 }
280}
281
282
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000283Operand LCodeGen::HighOperand(LOperand* op) {
284 ASSERT(op->IsDoubleStackSlot());
285 int index = op->index();
286 int offset = (index >= 0) ? index + 3 : index - 1;
287 return Operand(ebp, -offset * kPointerSize);
288}
289
290
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000291void LCodeGen::WriteTranslation(LEnvironment* environment,
292 Translation* translation) {
293 if (environment == NULL) return;
294
295 // The translation includes one command per value in the environment.
296 int translation_size = environment->values()->length();
297 // The output frame height does not include the parameters.
298 int height = translation_size - environment->parameter_count();
299
300 WriteTranslation(environment->outer(), translation);
301 int closure_id = DefineDeoptimizationLiteral(environment->closure());
302 translation->BeginFrame(environment->ast_id(), closure_id, height);
303 for (int i = 0; i < translation_size; ++i) {
304 LOperand* value = environment->values()->at(i);
305 // spilled_registers_ and spilled_double_registers_ are either
306 // both NULL or both set.
307 if (environment->spilled_registers() != NULL && value != NULL) {
308 if (value->IsRegister() &&
309 environment->spilled_registers()[value->index()] != NULL) {
310 translation->MarkDuplicate();
311 AddToTranslation(translation,
312 environment->spilled_registers()[value->index()],
313 environment->HasTaggedValueAt(i));
314 } else if (
315 value->IsDoubleRegister() &&
316 environment->spilled_double_registers()[value->index()] != NULL) {
317 translation->MarkDuplicate();
318 AddToTranslation(
319 translation,
320 environment->spilled_double_registers()[value->index()],
321 false);
322 }
323 }
324
325 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
326 }
327}
328
329
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000330void LCodeGen::AddToTranslation(Translation* translation,
331 LOperand* op,
332 bool is_tagged) {
333 if (op == NULL) {
334 // TODO(twuerthinger): Introduce marker operands to indicate that this value
335 // is not present and must be reconstructed from the deoptimizer. Currently
336 // this is only used for the arguments object.
337 translation->StoreArgumentsObject();
338 } else if (op->IsStackSlot()) {
339 if (is_tagged) {
340 translation->StoreStackSlot(op->index());
341 } else {
342 translation->StoreInt32StackSlot(op->index());
343 }
344 } else if (op->IsDoubleStackSlot()) {
345 translation->StoreDoubleStackSlot(op->index());
346 } else if (op->IsArgument()) {
347 ASSERT(is_tagged);
348 int src_index = StackSlotCount() + op->index();
349 translation->StoreStackSlot(src_index);
350 } else if (op->IsRegister()) {
351 Register reg = ToRegister(op);
352 if (is_tagged) {
353 translation->StoreRegister(reg);
354 } else {
355 translation->StoreInt32Register(reg);
356 }
357 } else if (op->IsDoubleRegister()) {
358 XMMRegister reg = ToDoubleRegister(op);
359 translation->StoreDoubleRegister(reg);
360 } else if (op->IsConstantOperand()) {
361 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
362 int src_index = DefineDeoptimizationLiteral(literal);
363 translation->StoreLiteral(src_index);
364 } else {
365 UNREACHABLE();
366 }
367}
368
369
370void LCodeGen::CallCode(Handle<Code> code,
371 RelocInfo::Mode mode,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000372 LInstruction* instr,
373 bool adjusted) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000374 ASSERT(instr != NULL);
375 LPointerMap* pointers = instr->pointer_map();
376 RecordPosition(pointers->position());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000377 if (!adjusted) {
378 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
379 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000380 __ call(code, mode);
381 RegisterLazyDeoptimization(instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000382
383 // Signal that we don't inline smi code before these stubs in the
384 // optimizing code generator.
385 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
386 code->kind() == Code::COMPARE_IC) {
387 __ nop();
388 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000389}
390
391
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000392void LCodeGen::CallRuntime(Runtime::Function* fun,
393 int argc,
394 LInstruction* instr,
395 bool adjusted) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000396 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000397 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000398 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000399 RecordPosition(pointers->position());
400
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000401 if (!adjusted) {
402 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
403 }
404 __ CallRuntime(fun, argc);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000405 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000406}
407
408
409void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
410 // Create the environment to bailout to. If the call has side effects
411 // execution has to continue after the call otherwise execution can continue
412 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000413 LEnvironment* deoptimization_environment;
414 if (instr->HasDeoptimizationEnvironment()) {
415 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000416 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000417 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000418 }
419
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000420 RegisterEnvironmentForDeoptimization(deoptimization_environment);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000421 RecordSafepoint(instr->pointer_map(),
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000422 deoptimization_environment->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000423}
424
425
426void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
427 if (!environment->HasBeenRegistered()) {
428 // Physical stack frame layout:
429 // -x ............. -4 0 ..................................... y
430 // [incoming arguments] [spill slots] [pushed outgoing arguments]
431
432 // Layout of the environment:
433 // 0 ..................................................... size-1
434 // [parameters] [locals] [expression stack including arguments]
435
436 // Layout of the translation:
437 // 0 ........................................................ size - 1 + 4
438 // [expression stack including arguments] [locals] [4 words] [parameters]
439 // |>------------ translation_size ------------<|
440
441 int frame_count = 0;
442 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
443 ++frame_count;
444 }
445 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000446 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 int deoptimization_index = deoptimizations_.length();
448 environment->Register(deoptimization_index, translation.index());
449 deoptimizations_.Add(environment);
450 }
451}
452
453
454void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
455 RegisterEnvironmentForDeoptimization(environment);
456 ASSERT(environment->HasBeenRegistered());
457 int id = environment->deoptimization_index();
458 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
459 ASSERT(entry != NULL);
460 if (entry == NULL) {
461 Abort("bailout was not prepared");
462 return;
463 }
464
465 if (FLAG_deopt_every_n_times != 0) {
466 Handle<SharedFunctionInfo> shared(info_->shared_info());
467 Label no_deopt;
468 __ pushfd();
469 __ push(eax);
470 __ push(ebx);
471 __ mov(ebx, shared);
472 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
473 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
474 __ j(not_zero, &no_deopt);
475 if (FLAG_trap_on_deopt) __ int3();
476 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
477 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
478 __ pop(ebx);
479 __ pop(eax);
480 __ popfd();
481 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
482
483 __ bind(&no_deopt);
484 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
485 __ pop(ebx);
486 __ pop(eax);
487 __ popfd();
488 }
489
490 if (cc == no_condition) {
491 if (FLAG_trap_on_deopt) __ int3();
492 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
493 } else {
494 if (FLAG_trap_on_deopt) {
495 NearLabel done;
496 __ j(NegateCondition(cc), &done);
497 __ int3();
498 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
499 __ bind(&done);
500 } else {
501 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY, not_taken);
502 }
503 }
504}
505
506
507void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
508 int length = deoptimizations_.length();
509 if (length == 0) return;
510 ASSERT(FLAG_deopt);
511 Handle<DeoptimizationInputData> data =
512 Factory::NewDeoptimizationInputData(length, TENURED);
513
514 data->SetTranslationByteArray(*translations_.CreateByteArray());
515 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
516
517 Handle<FixedArray> literals =
518 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
519 for (int i = 0; i < deoptimization_literals_.length(); i++) {
520 literals->set(i, *deoptimization_literals_[i]);
521 }
522 data->SetLiteralArray(*literals);
523
524 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
525 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
526
527 // Populate the deoptimization entries.
528 for (int i = 0; i < length; i++) {
529 LEnvironment* env = deoptimizations_[i];
530 data->SetAstId(i, Smi::FromInt(env->ast_id()));
531 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
532 data->SetArgumentsStackHeight(i,
533 Smi::FromInt(env->arguments_stack_height()));
534 }
535 code->set_deoptimization_data(*data);
536}
537
538
539int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
540 int result = deoptimization_literals_.length();
541 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
542 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
543 }
544 deoptimization_literals_.Add(literal);
545 return result;
546}
547
548
549void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
550 ASSERT(deoptimization_literals_.length() == 0);
551
552 const ZoneList<Handle<JSFunction> >* inlined_closures =
553 chunk()->inlined_closures();
554
555 for (int i = 0, length = inlined_closures->length();
556 i < length;
557 i++) {
558 DefineDeoptimizationLiteral(inlined_closures->at(i));
559 }
560
561 inlined_function_count_ = deoptimization_literals_.length();
562}
563
564
ager@chromium.org378b34e2011-01-28 08:04:38 +0000565void LCodeGen::RecordSafepoint(
566 LPointerMap* pointers,
567 Safepoint::Kind kind,
568 int arguments,
569 int deoptimization_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000570 const ZoneList<LOperand*>* operands = pointers->operands();
571 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000572 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000573 for (int i = 0; i < operands->length(); i++) {
574 LOperand* pointer = operands->at(i);
575 if (pointer->IsStackSlot()) {
576 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000577 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
578 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000579 }
580 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000581}
582
583
584void LCodeGen::RecordSafepoint(LPointerMap* pointers,
585 int deoptimization_index) {
586 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000587}
588
589
590void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
591 int arguments,
592 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000593 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
594 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000595}
596
597
598void LCodeGen::RecordPosition(int position) {
599 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
600 masm()->positions_recorder()->RecordPosition(position);
601}
602
603
604void LCodeGen::DoLabel(LLabel* label) {
605 if (label->is_loop_header()) {
606 Comment(";;; B%d - LOOP entry", label->block_id());
607 } else {
608 Comment(";;; B%d", label->block_id());
609 }
610 __ bind(label->label());
611 current_block_ = label->block_id();
612 LCodeGen::DoGap(label);
613}
614
615
616void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000617 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000618}
619
620
621void LCodeGen::DoGap(LGap* gap) {
622 for (int i = LGap::FIRST_INNER_POSITION;
623 i <= LGap::LAST_INNER_POSITION;
624 i++) {
625 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
626 LParallelMove* move = gap->GetParallelMove(inner_pos);
627 if (move != NULL) DoParallelMove(move);
628 }
629
630 LInstruction* next = GetNextInstruction();
631 if (next != NULL && next->IsLazyBailout()) {
632 int pc = masm()->pc_offset();
633 safepoints_.SetPcAfterGap(pc);
634 }
635}
636
637
638void LCodeGen::DoParameter(LParameter* instr) {
639 // Nothing to do.
640}
641
642
643void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000644 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000645 ASSERT(ToRegister(instr->result()).is(eax));
646 switch (instr->hydrogen()->major_key()) {
647 case CodeStub::RegExpConstructResult: {
648 RegExpConstructResultStub stub;
649 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
650 break;
651 }
652 case CodeStub::RegExpExec: {
653 RegExpExecStub stub;
654 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
655 break;
656 }
657 case CodeStub::SubString: {
658 SubStringStub stub;
659 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
660 break;
661 }
662 case CodeStub::StringCharAt: {
663 StringCharAtStub stub;
664 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
665 break;
666 }
667 case CodeStub::MathPow: {
668 MathPowStub stub;
669 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
670 break;
671 }
672 case CodeStub::NumberToString: {
673 NumberToStringStub stub;
674 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
675 break;
676 }
677 case CodeStub::StringAdd: {
678 StringAddStub stub(NO_STRING_ADD_FLAGS);
679 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
680 break;
681 }
682 case CodeStub::StringCompare: {
683 StringCompareStub stub;
684 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
685 break;
686 }
687 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000688 TranscendentalCacheStub stub(instr->transcendental_type(),
689 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000690 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
691 break;
692 }
693 default:
694 UNREACHABLE();
695 }
696}
697
698
699void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
700 // Nothing to do.
701}
702
703
704void LCodeGen::DoModI(LModI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000705 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000706 ASSERT(ToRegister(instr->result()).is(edx));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000707 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
708 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
709 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000710
711 Register right_reg = ToRegister(right);
712
713 // Check for x % 0.
714 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
715 __ test(right_reg, ToOperand(right));
716 DeoptimizeIf(zero, instr->environment());
717 }
718
719 // Sign extend to edx.
720 __ cdq();
721
722 // Check for (0 % -x) that will produce negative zero.
723 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
724 NearLabel positive_left;
725 NearLabel done;
726 __ test(eax, Operand(eax));
727 __ j(not_sign, &positive_left);
728 __ idiv(right_reg);
729
730 // Test the remainder for 0, because then the result would be -0.
731 __ test(edx, Operand(edx));
732 __ j(not_zero, &done);
733
734 DeoptimizeIf(no_condition, instr->environment());
735 __ bind(&positive_left);
736 __ idiv(right_reg);
737 __ bind(&done);
738 } else {
739 __ idiv(right_reg);
740 }
741}
742
743
744void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000745 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000747 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
748 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
749 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750
751 Register left_reg = eax;
752
753 // Check for x / 0.
754 Register right_reg = ToRegister(right);
755 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
756 __ test(right_reg, ToOperand(right));
757 DeoptimizeIf(zero, instr->environment());
758 }
759
760 // Check for (0 / -x) that will produce negative zero.
761 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
762 NearLabel left_not_zero;
763 __ test(left_reg, Operand(left_reg));
764 __ j(not_zero, &left_not_zero);
765 __ test(right_reg, ToOperand(right));
766 DeoptimizeIf(sign, instr->environment());
767 __ bind(&left_not_zero);
768 }
769
770 // Check for (-kMinInt / -1).
771 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
772 NearLabel left_not_min_int;
773 __ cmp(left_reg, kMinInt);
774 __ j(not_zero, &left_not_min_int);
775 __ cmp(right_reg, -1);
776 DeoptimizeIf(zero, instr->environment());
777 __ bind(&left_not_min_int);
778 }
779
780 // Sign extend to edx.
781 __ cdq();
782 __ idiv(right_reg);
783
784 // Deoptimize if remainder is not 0.
785 __ test(edx, Operand(edx));
786 DeoptimizeIf(not_zero, instr->environment());
787}
788
789
790void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000791 Register left = ToRegister(instr->InputAt(0));
792 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793
794 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000795 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000796 }
797
798 if (right->IsConstantOperand()) {
799 __ imul(left, left, ToInteger32(LConstantOperand::cast(right)));
800 } else {
801 __ imul(left, ToOperand(right));
802 }
803
804 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
805 DeoptimizeIf(overflow, instr->environment());
806 }
807
808 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
809 // Bail out if the result is supposed to be negative zero.
810 NearLabel done;
811 __ test(left, Operand(left));
812 __ j(not_zero, &done);
813 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000814 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000815 DeoptimizeIf(no_condition, instr->environment());
816 }
817 } else {
818 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000819 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000820 DeoptimizeIf(sign, instr->environment());
821 }
822 __ bind(&done);
823 }
824}
825
826
827void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000828 LOperand* left = instr->InputAt(0);
829 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000830 ASSERT(left->Equals(instr->result()));
831 ASSERT(left->IsRegister());
832
833 if (right->IsConstantOperand()) {
834 int right_operand = ToInteger32(LConstantOperand::cast(right));
835 switch (instr->op()) {
836 case Token::BIT_AND:
837 __ and_(ToRegister(left), right_operand);
838 break;
839 case Token::BIT_OR:
840 __ or_(ToRegister(left), right_operand);
841 break;
842 case Token::BIT_XOR:
843 __ xor_(ToRegister(left), right_operand);
844 break;
845 default:
846 UNREACHABLE();
847 break;
848 }
849 } else {
850 switch (instr->op()) {
851 case Token::BIT_AND:
852 __ and_(ToRegister(left), ToOperand(right));
853 break;
854 case Token::BIT_OR:
855 __ or_(ToRegister(left), ToOperand(right));
856 break;
857 case Token::BIT_XOR:
858 __ xor_(ToRegister(left), ToOperand(right));
859 break;
860 default:
861 UNREACHABLE();
862 break;
863 }
864 }
865}
866
867
868void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000869 LOperand* left = instr->InputAt(0);
870 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000871 ASSERT(left->Equals(instr->result()));
872 ASSERT(left->IsRegister());
873 if (right->IsRegister()) {
874 ASSERT(ToRegister(right).is(ecx));
875
876 switch (instr->op()) {
877 case Token::SAR:
878 __ sar_cl(ToRegister(left));
879 break;
880 case Token::SHR:
881 __ shr_cl(ToRegister(left));
882 if (instr->can_deopt()) {
883 __ test(ToRegister(left), Immediate(0x80000000));
884 DeoptimizeIf(not_zero, instr->environment());
885 }
886 break;
887 case Token::SHL:
888 __ shl_cl(ToRegister(left));
889 break;
890 default:
891 UNREACHABLE();
892 break;
893 }
894 } else {
895 int value = ToInteger32(LConstantOperand::cast(right));
896 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
897 switch (instr->op()) {
898 case Token::SAR:
899 if (shift_count != 0) {
900 __ sar(ToRegister(left), shift_count);
901 }
902 break;
903 case Token::SHR:
904 if (shift_count == 0 && instr->can_deopt()) {
905 __ test(ToRegister(left), Immediate(0x80000000));
906 DeoptimizeIf(not_zero, instr->environment());
907 } else {
908 __ shr(ToRegister(left), shift_count);
909 }
910 break;
911 case Token::SHL:
912 if (shift_count != 0) {
913 __ shl(ToRegister(left), shift_count);
914 }
915 break;
916 default:
917 UNREACHABLE();
918 break;
919 }
920 }
921}
922
923
924void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000925 LOperand* left = instr->InputAt(0);
926 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927 ASSERT(left->Equals(instr->result()));
928
929 if (right->IsConstantOperand()) {
930 __ sub(ToOperand(left), ToImmediate(right));
931 } else {
932 __ sub(ToRegister(left), ToOperand(right));
933 }
934 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
935 DeoptimizeIf(overflow, instr->environment());
936 }
937}
938
939
940void LCodeGen::DoConstantI(LConstantI* instr) {
941 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000942 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000943}
944
945
946void LCodeGen::DoConstantD(LConstantD* instr) {
947 ASSERT(instr->result()->IsDoubleRegister());
948 XMMRegister res = ToDoubleRegister(instr->result());
949 double v = instr->value();
950 // Use xor to produce +0.0 in a fast and compact way, but avoid to
951 // do so if the constant is -0.0.
952 if (BitCast<uint64_t, double>(v) == 0) {
953 __ xorpd(res, res);
954 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000955 Register temp = ToRegister(instr->TempAt(0));
956 uint64_t int_val = BitCast<uint64_t, double>(v);
957 int32_t lower = static_cast<int32_t>(int_val);
958 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
959 if (CpuFeatures::IsSupported(SSE4_1)) {
960 CpuFeatures::Scope scope(SSE4_1);
961 if (lower != 0) {
962 __ Set(temp, Immediate(lower));
963 __ movd(res, Operand(temp));
964 __ Set(temp, Immediate(upper));
965 __ pinsrd(res, Operand(temp), 1);
966 } else {
967 __ xorpd(res, res);
968 __ Set(temp, Immediate(upper));
969 __ pinsrd(res, Operand(temp), 1);
970 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000971 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000972 __ Set(temp, Immediate(upper));
973 __ movd(res, Operand(temp));
974 __ psllq(res, 32);
975 if (lower != 0) {
976 __ Set(temp, Immediate(lower));
977 __ movd(xmm0, Operand(temp));
978 __ por(res, xmm0);
979 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000980 }
981 }
982}
983
984
985void LCodeGen::DoConstantT(LConstantT* instr) {
986 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000987 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000988}
989
990
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000991void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000992 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000993 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000994 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
995}
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000997
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000998void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
999 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001000 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001001 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001002}
1003
1004
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001005void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
1006 Register result = ToRegister(instr->result());
1007 Register array = ToRegister(instr->InputAt(0));
1008 __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
1009}
1010
1011
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001012void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001013 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001015 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016 ASSERT(input.is(result));
1017 NearLabel done;
1018 // If the object is a smi return the object.
1019 __ test(input, Immediate(kSmiTagMask));
1020 __ j(zero, &done);
1021
1022 // If the object is not a value type, return the object.
1023 __ CmpObjectType(input, JS_VALUE_TYPE, map);
1024 __ j(not_equal, &done);
1025 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1026
1027 __ bind(&done);
1028}
1029
1030
1031void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001032 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 ASSERT(input->Equals(instr->result()));
1034 __ not_(ToRegister(input));
1035}
1036
1037
1038void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001039 __ push(ToOperand(instr->InputAt(0)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001040 CallRuntime(Runtime::kThrow, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001041
1042 if (FLAG_debug_code) {
1043 Comment("Unreachable code.");
1044 __ int3();
1045 }
1046}
1047
1048
1049void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001050 LOperand* left = instr->InputAt(0);
1051 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001052 ASSERT(left->Equals(instr->result()));
1053
1054 if (right->IsConstantOperand()) {
1055 __ add(ToOperand(left), ToImmediate(right));
1056 } else {
1057 __ add(ToRegister(left), ToOperand(right));
1058 }
1059
1060 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1061 DeoptimizeIf(overflow, instr->environment());
1062 }
1063}
1064
1065
1066void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001067 LOperand* left = instr->InputAt(0);
1068 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001069 // Modulo uses a fixed result register.
1070 ASSERT(instr->op() == Token::MOD || left->Equals(instr->result()));
1071 switch (instr->op()) {
1072 case Token::ADD:
1073 __ addsd(ToDoubleRegister(left), ToDoubleRegister(right));
1074 break;
1075 case Token::SUB:
1076 __ subsd(ToDoubleRegister(left), ToDoubleRegister(right));
1077 break;
1078 case Token::MUL:
1079 __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right));
1080 break;
1081 case Token::DIV:
1082 __ divsd(ToDoubleRegister(left), ToDoubleRegister(right));
1083 break;
1084 case Token::MOD: {
1085 // Pass two doubles as arguments on the stack.
1086 __ PrepareCallCFunction(4, eax);
1087 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
1088 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
1089 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
1090
1091 // Return value is in st(0) on ia32.
1092 // Store it into the (fixed) result register.
1093 __ sub(Operand(esp), Immediate(kDoubleSize));
1094 __ fstp_d(Operand(esp, 0));
1095 __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
1096 __ add(Operand(esp), Immediate(kDoubleSize));
1097 break;
1098 }
1099 default:
1100 UNREACHABLE();
1101 break;
1102 }
1103}
1104
1105
1106void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001107 ASSERT(ToRegister(instr->InputAt(0)).is(edx));
1108 ASSERT(ToRegister(instr->InputAt(1)).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001109 ASSERT(ToRegister(instr->result()).is(eax));
1110
1111 TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001112 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001113}
1114
1115
1116int LCodeGen::GetNextEmittedBlock(int block) {
1117 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1118 LLabel* label = chunk_->GetLabel(i);
1119 if (!label->HasReplacement()) return i;
1120 }
1121 return -1;
1122}
1123
1124
1125void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1126 int next_block = GetNextEmittedBlock(current_block_);
1127 right_block = chunk_->LookupDestination(right_block);
1128 left_block = chunk_->LookupDestination(left_block);
1129
1130 if (right_block == left_block) {
1131 EmitGoto(left_block);
1132 } else if (left_block == next_block) {
1133 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1134 } else if (right_block == next_block) {
1135 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1136 } else {
1137 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1138 __ jmp(chunk_->GetAssemblyLabel(right_block));
1139 }
1140}
1141
1142
1143void LCodeGen::DoBranch(LBranch* instr) {
1144 int true_block = chunk_->LookupDestination(instr->true_block_id());
1145 int false_block = chunk_->LookupDestination(instr->false_block_id());
1146
1147 Representation r = instr->hydrogen()->representation();
1148 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001149 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001150 __ test(reg, Operand(reg));
1151 EmitBranch(true_block, false_block, not_zero);
1152 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001153 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001154 __ xorpd(xmm0, xmm0);
1155 __ ucomisd(reg, xmm0);
1156 EmitBranch(true_block, false_block, not_equal);
1157 } else {
1158 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001159 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001160 if (instr->hydrogen()->type().IsBoolean()) {
1161 __ cmp(reg, Factory::true_value());
1162 EmitBranch(true_block, false_block, equal);
1163 } else {
1164 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1165 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1166
1167 __ cmp(reg, Factory::undefined_value());
1168 __ j(equal, false_label);
1169 __ cmp(reg, Factory::true_value());
1170 __ j(equal, true_label);
1171 __ cmp(reg, Factory::false_value());
1172 __ j(equal, false_label);
1173 __ test(reg, Operand(reg));
1174 __ j(equal, false_label);
1175 __ test(reg, Immediate(kSmiTagMask));
1176 __ j(zero, true_label);
1177
1178 // Test for double values. Zero is false.
1179 NearLabel call_stub;
1180 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1181 Factory::heap_number_map());
1182 __ j(not_equal, &call_stub);
1183 __ fldz();
1184 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1185 __ FCmp();
1186 __ j(zero, false_label);
1187 __ jmp(true_label);
1188
1189 // The conversion stub doesn't cause garbage collections so it's
1190 // safe to not record a safepoint after the call.
1191 __ bind(&call_stub);
1192 ToBooleanStub stub;
1193 __ pushad();
1194 __ push(reg);
1195 __ CallStub(&stub);
1196 __ test(eax, Operand(eax));
1197 __ popad();
1198 EmitBranch(true_block, false_block, not_zero);
1199 }
1200 }
1201}
1202
1203
1204void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
1205 block = chunk_->LookupDestination(block);
1206 int next_block = GetNextEmittedBlock(current_block_);
1207 if (block != next_block) {
1208 // Perform stack overflow check if this goto needs it before jumping.
1209 if (deferred_stack_check != NULL) {
1210 ExternalReference stack_limit =
1211 ExternalReference::address_of_stack_limit();
1212 __ cmp(esp, Operand::StaticVariable(stack_limit));
1213 __ j(above_equal, chunk_->GetAssemblyLabel(block));
1214 __ jmp(deferred_stack_check->entry());
1215 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1216 } else {
1217 __ jmp(chunk_->GetAssemblyLabel(block));
1218 }
1219 }
1220}
1221
1222
1223void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
1224 __ pushad();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001225 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001226 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
1227 RecordSafepointWithRegisters(
1228 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1229 __ popad();
1230}
1231
1232void LCodeGen::DoGoto(LGoto* instr) {
1233 class DeferredStackCheck: public LDeferredCode {
1234 public:
1235 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1236 : LDeferredCode(codegen), instr_(instr) { }
1237 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1238 private:
1239 LGoto* instr_;
1240 };
1241
1242 DeferredStackCheck* deferred = NULL;
1243 if (instr->include_stack_check()) {
1244 deferred = new DeferredStackCheck(this, instr);
1245 }
1246 EmitGoto(instr->block_id(), deferred);
1247}
1248
1249
1250Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1251 Condition cond = no_condition;
1252 switch (op) {
1253 case Token::EQ:
1254 case Token::EQ_STRICT:
1255 cond = equal;
1256 break;
1257 case Token::LT:
1258 cond = is_unsigned ? below : less;
1259 break;
1260 case Token::GT:
1261 cond = is_unsigned ? above : greater;
1262 break;
1263 case Token::LTE:
1264 cond = is_unsigned ? below_equal : less_equal;
1265 break;
1266 case Token::GTE:
1267 cond = is_unsigned ? above_equal : greater_equal;
1268 break;
1269 case Token::IN:
1270 case Token::INSTANCEOF:
1271 default:
1272 UNREACHABLE();
1273 }
1274 return cond;
1275}
1276
1277
1278void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
1279 if (right->IsConstantOperand()) {
1280 __ cmp(ToOperand(left), ToImmediate(right));
1281 } else {
1282 __ cmp(ToRegister(left), ToOperand(right));
1283 }
1284}
1285
1286
1287void LCodeGen::DoCmpID(LCmpID* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001288 LOperand* left = instr->InputAt(0);
1289 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001290 LOperand* result = instr->result();
1291
1292 NearLabel unordered;
1293 if (instr->is_double()) {
1294 // Don't base result on EFLAGS when a NaN is involved. Instead
1295 // jump to the unordered case, which produces a false value.
1296 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1297 __ j(parity_even, &unordered, not_taken);
1298 } else {
1299 EmitCmpI(left, right);
1300 }
1301
1302 NearLabel done;
1303 Condition cc = TokenToCondition(instr->op(), instr->is_double());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001304 __ mov(ToRegister(result), Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001305 __ j(cc, &done);
1306
1307 __ bind(&unordered);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001308 __ mov(ToRegister(result), Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309 __ bind(&done);
1310}
1311
1312
1313void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001314 LOperand* left = instr->InputAt(0);
1315 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001316 int false_block = chunk_->LookupDestination(instr->false_block_id());
1317 int true_block = chunk_->LookupDestination(instr->true_block_id());
1318
1319 if (instr->is_double()) {
1320 // Don't base result on EFLAGS when a NaN is involved. Instead
1321 // jump to the false block.
1322 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1323 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1324 } else {
1325 EmitCmpI(left, right);
1326 }
1327
1328 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1329 EmitBranch(true_block, false_block, cc);
1330}
1331
1332
1333void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001334 Register left = ToRegister(instr->InputAt(0));
1335 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001336 Register result = ToRegister(instr->result());
1337
1338 __ cmp(left, Operand(right));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001339 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001340 NearLabel done;
1341 __ j(equal, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001342 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343 __ bind(&done);
1344}
1345
1346
1347void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001348 Register left = ToRegister(instr->InputAt(0));
1349 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001350 int false_block = chunk_->LookupDestination(instr->false_block_id());
1351 int true_block = chunk_->LookupDestination(instr->true_block_id());
1352
1353 __ cmp(left, Operand(right));
1354 EmitBranch(true_block, false_block, equal);
1355}
1356
1357
1358void LCodeGen::DoIsNull(LIsNull* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001359 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001360 Register result = ToRegister(instr->result());
1361
1362 // TODO(fsc): If the expression is known to be a smi, then it's
1363 // definitely not null. Materialize false.
1364
1365 __ cmp(reg, Factory::null_value());
1366 if (instr->is_strict()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001367 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001368 NearLabel done;
1369 __ j(equal, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001370 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001371 __ bind(&done);
1372 } else {
1373 NearLabel true_value, false_value, done;
1374 __ j(equal, &true_value);
1375 __ cmp(reg, Factory::undefined_value());
1376 __ j(equal, &true_value);
1377 __ test(reg, Immediate(kSmiTagMask));
1378 __ j(zero, &false_value);
1379 // Check for undetectable objects by looking in the bit field in
1380 // the map. The object has already been smi checked.
1381 Register scratch = result;
1382 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1383 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1384 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1385 __ j(not_zero, &true_value);
1386 __ bind(&false_value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001387 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388 __ jmp(&done);
1389 __ bind(&true_value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001390 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001391 __ bind(&done);
1392 }
1393}
1394
1395
1396void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001397 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001398
1399 // TODO(fsc): If the expression is known to be a smi, then it's
1400 // definitely not null. Jump to the false block.
1401
1402 int true_block = chunk_->LookupDestination(instr->true_block_id());
1403 int false_block = chunk_->LookupDestination(instr->false_block_id());
1404
1405 __ cmp(reg, Factory::null_value());
1406 if (instr->is_strict()) {
1407 EmitBranch(true_block, false_block, equal);
1408 } else {
1409 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1410 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1411 __ j(equal, true_label);
1412 __ cmp(reg, Factory::undefined_value());
1413 __ j(equal, true_label);
1414 __ test(reg, Immediate(kSmiTagMask));
1415 __ j(zero, false_label);
1416 // Check for undetectable objects by looking in the bit field in
1417 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001418 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1420 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1421 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1422 EmitBranch(true_block, false_block, not_zero);
1423 }
1424}
1425
1426
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001427Condition LCodeGen::EmitIsObject(Register input,
1428 Register temp1,
1429 Register temp2,
1430 Label* is_not_object,
1431 Label* is_object) {
1432 ASSERT(!input.is(temp1));
1433 ASSERT(!input.is(temp2));
1434 ASSERT(!temp1.is(temp2));
1435
1436 __ test(input, Immediate(kSmiTagMask));
1437 __ j(equal, is_not_object);
1438
1439 __ cmp(input, Factory::null_value());
1440 __ j(equal, is_object);
1441
1442 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1443 // Undetectable objects behave like undefined.
1444 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
1445 __ test(temp2, Immediate(1 << Map::kIsUndetectable));
1446 __ j(not_zero, is_not_object);
1447
1448 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
1449 __ cmp(temp2, FIRST_JS_OBJECT_TYPE);
1450 __ j(below, is_not_object);
1451 __ cmp(temp2, LAST_JS_OBJECT_TYPE);
1452 return below_equal;
1453}
1454
1455
1456void LCodeGen::DoIsObject(LIsObject* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001457 Register reg = ToRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001458 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001459 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001460 Label is_false, is_true, done;
1461
1462 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1463 __ j(true_cond, &is_true);
1464
1465 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001466 __ mov(result, Factory::false_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001467 __ jmp(&done);
1468
1469 __ bind(&is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001470 __ mov(result, Factory::true_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001471
1472 __ bind(&done);
1473}
1474
1475
1476void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001477 Register reg = ToRegister(instr->InputAt(0));
1478 Register temp = ToRegister(instr->TempAt(0));
1479 Register temp2 = ToRegister(instr->TempAt(1));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001480
1481 int true_block = chunk_->LookupDestination(instr->true_block_id());
1482 int false_block = chunk_->LookupDestination(instr->false_block_id());
1483 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1484 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1485
1486 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
1487
1488 EmitBranch(true_block, false_block, true_cond);
1489}
1490
1491
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001492void LCodeGen::DoIsSmi(LIsSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001493 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001494 Register result = ToRegister(instr->result());
1495
1496 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1497 __ test(input, Immediate(kSmiTagMask));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001498 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001499 NearLabel done;
1500 __ j(zero, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001501 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 __ bind(&done);
1503}
1504
1505
1506void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001507 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001508
1509 int true_block = chunk_->LookupDestination(instr->true_block_id());
1510 int false_block = chunk_->LookupDestination(instr->false_block_id());
1511
1512 __ test(input, Immediate(kSmiTagMask));
1513 EmitBranch(true_block, false_block, zero);
1514}
1515
1516
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001517static InstanceType TestType(HHasInstanceType* instr) {
1518 InstanceType from = instr->from();
1519 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520 if (from == FIRST_TYPE) return to;
1521 ASSERT(from == to || to == LAST_TYPE);
1522 return from;
1523}
1524
1525
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001526static Condition BranchCondition(HHasInstanceType* instr) {
1527 InstanceType from = instr->from();
1528 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529 if (from == to) return equal;
1530 if (to == LAST_TYPE) return above_equal;
1531 if (from == FIRST_TYPE) return below_equal;
1532 UNREACHABLE();
1533 return equal;
1534}
1535
1536
1537void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001538 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001539 Register result = ToRegister(instr->result());
1540
1541 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1542 __ test(input, Immediate(kSmiTagMask));
1543 NearLabel done, is_false;
1544 __ j(zero, &is_false);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001545 __ CmpObjectType(input, TestType(instr->hydrogen()), result);
1546 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001547 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001548 __ jmp(&done);
1549 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001550 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001551 __ bind(&done);
1552}
1553
1554
1555void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001556 Register input = ToRegister(instr->InputAt(0));
1557 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001558
1559 int true_block = chunk_->LookupDestination(instr->true_block_id());
1560 int false_block = chunk_->LookupDestination(instr->false_block_id());
1561
1562 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1563
1564 __ test(input, Immediate(kSmiTagMask));
1565 __ j(zero, false_label);
1566
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001567 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1568 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001569}
1570
1571
1572void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001573 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001574 Register result = ToRegister(instr->result());
1575
1576 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001577 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001578 __ test(FieldOperand(input, String::kHashFieldOffset),
1579 Immediate(String::kContainsCachedArrayIndexMask));
1580 NearLabel done;
1581 __ j(not_zero, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001582 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 __ bind(&done);
1584}
1585
1586
1587void LCodeGen::DoHasCachedArrayIndexAndBranch(
1588 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001589 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001590
1591 int true_block = chunk_->LookupDestination(instr->true_block_id());
1592 int false_block = chunk_->LookupDestination(instr->false_block_id());
1593
1594 __ test(FieldOperand(input, String::kHashFieldOffset),
1595 Immediate(String::kContainsCachedArrayIndexMask));
1596 EmitBranch(true_block, false_block, not_equal);
1597}
1598
1599
1600// Branches to a label or falls through with the answer in the z flag. Trashes
1601// the temp registers, but not the input. Only input and temp2 may alias.
1602void LCodeGen::EmitClassOfTest(Label* is_true,
1603 Label* is_false,
1604 Handle<String>class_name,
1605 Register input,
1606 Register temp,
1607 Register temp2) {
1608 ASSERT(!input.is(temp));
1609 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
1610 __ test(input, Immediate(kSmiTagMask));
1611 __ j(zero, is_false);
1612 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
1613 __ j(below, is_false);
1614
1615 // Map is now in temp.
1616 // Functions have class 'Function'.
1617 __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
1618 if (class_name->IsEqualTo(CStrVector("Function"))) {
1619 __ j(equal, is_true);
1620 } else {
1621 __ j(equal, is_false);
1622 }
1623
1624 // Check if the constructor in the map is a function.
1625 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
1626
1627 // As long as JS_FUNCTION_TYPE is the last instance type and it is
1628 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1629 // LAST_JS_OBJECT_TYPE.
1630 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1631 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
1632
1633 // Objects with a non-function constructor have class 'Object'.
1634 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1635 if (class_name->IsEqualTo(CStrVector("Object"))) {
1636 __ j(not_equal, is_true);
1637 } else {
1638 __ j(not_equal, is_false);
1639 }
1640
1641 // temp now contains the constructor function. Grab the
1642 // instance class name from there.
1643 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1644 __ mov(temp, FieldOperand(temp,
1645 SharedFunctionInfo::kInstanceClassNameOffset));
1646 // The class name we are testing against is a symbol because it's a literal.
1647 // The name in the constructor is a symbol because of the way the context is
1648 // booted. This routine isn't expected to work for random API-created
1649 // classes and it doesn't have to because you can't access it with natives
1650 // syntax. Since both sides are symbols it is sufficient to use an identity
1651 // comparison.
1652 __ cmp(temp, class_name);
1653 // End with the answer in the z flag.
1654}
1655
1656
1657void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001658 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001659 Register result = ToRegister(instr->result());
1660 ASSERT(input.is(result));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001661 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001662 Handle<String> class_name = instr->hydrogen()->class_name();
1663 NearLabel done;
1664 Label is_true, is_false;
1665
1666 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
1667
1668 __ j(not_equal, &is_false);
1669
1670 __ bind(&is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001671 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001672 __ jmp(&done);
1673
1674 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001675 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001676 __ bind(&done);
1677}
1678
1679
1680void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001681 Register input = ToRegister(instr->InputAt(0));
1682 Register temp = ToRegister(instr->TempAt(0));
1683 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001684 if (input.is(temp)) {
1685 // Swap.
1686 Register swapper = temp;
1687 temp = temp2;
1688 temp2 = swapper;
1689 }
1690 Handle<String> class_name = instr->hydrogen()->class_name();
1691
1692 int true_block = chunk_->LookupDestination(instr->true_block_id());
1693 int false_block = chunk_->LookupDestination(instr->false_block_id());
1694
1695 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1696 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1697
1698 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1699
1700 EmitBranch(true_block, false_block, equal);
1701}
1702
1703
1704void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001705 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001706 int true_block = instr->true_block_id();
1707 int false_block = instr->false_block_id();
1708
1709 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1710 EmitBranch(true_block, false_block, equal);
1711}
1712
1713
1714void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001715 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001716 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001717 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001718 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1719
1720 NearLabel true_value, done;
1721 __ test(eax, Operand(eax));
1722 __ j(zero, &true_value);
1723 __ mov(ToRegister(instr->result()), Factory::false_value());
1724 __ jmp(&done);
1725 __ bind(&true_value);
1726 __ mov(ToRegister(instr->result()), Factory::true_value());
1727 __ bind(&done);
1728}
1729
1730
1731void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001732 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001733 int true_block = chunk_->LookupDestination(instr->true_block_id());
1734 int false_block = chunk_->LookupDestination(instr->false_block_id());
1735
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001736 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001737 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1738 __ test(eax, Operand(eax));
1739 EmitBranch(true_block, false_block, zero);
1740}
1741
1742
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001743void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1744 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1745 public:
1746 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1747 LInstanceOfKnownGlobal* instr)
1748 : LDeferredCode(codegen), instr_(instr) { }
1749 virtual void Generate() {
1750 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
1751 }
1752
1753 Label* map_check() { return &map_check_; }
1754
1755 private:
1756 LInstanceOfKnownGlobal* instr_;
1757 Label map_check_;
1758 };
1759
1760 DeferredInstanceOfKnownGlobal* deferred;
1761 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1762
1763 Label done, false_result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001764 Register object = ToRegister(instr->InputAt(0));
1765 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001766
1767 // A Smi is not instance of anything.
1768 __ test(object, Immediate(kSmiTagMask));
1769 __ j(zero, &false_result, not_taken);
1770
1771 // This is the inlined call site instanceof cache. The two occourences of the
1772 // hole value will be patched to the last map/result pair generated by the
1773 // instanceof stub.
1774 NearLabel cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001775 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001776 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
1777 __ bind(deferred->map_check()); // Label for calculating code patching.
1778 __ cmp(map, Factory::the_hole_value()); // Patched to cached map.
1779 __ j(not_equal, &cache_miss, not_taken);
1780 __ mov(eax, Factory::the_hole_value()); // Patched to either true or false.
1781 __ jmp(&done);
1782
1783 // The inlined call site cache did not match. Check null and string before
1784 // calling the deferred code.
1785 __ bind(&cache_miss);
1786 // Null is not instance of anything.
1787 __ cmp(object, Factory::null_value());
1788 __ j(equal, &false_result);
1789
1790 // String values are not instances of anything.
1791 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
1792 __ j(is_string, &false_result);
1793
1794 // Go to the deferred code.
1795 __ jmp(deferred->entry());
1796
1797 __ bind(&false_result);
1798 __ mov(ToRegister(instr->result()), Factory::false_value());
1799
1800 // Here result has either true or false. Deferred code also produces true or
1801 // false object.
1802 __ bind(deferred->exit());
1803 __ bind(&done);
1804}
1805
1806
1807void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
1808 Label* map_check) {
1809 __ PushSafepointRegisters();
1810
1811 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
1812 flags = static_cast<InstanceofStub::Flags>(
1813 flags | InstanceofStub::kArgsInRegisters);
1814 flags = static_cast<InstanceofStub::Flags>(
1815 flags | InstanceofStub::kCallSiteInlineCheck);
1816 flags = static_cast<InstanceofStub::Flags>(
1817 flags | InstanceofStub::kReturnTrueFalseObject);
1818 InstanceofStub stub(flags);
1819
1820 // Get the temp register reserved by the instruction. This needs to be edi as
1821 // its slot of the pushing of safepoint registers is used to communicate the
1822 // offset to the location of the map check.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001823 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 ASSERT(temp.is(edi));
1825 __ mov(InstanceofStub::right(), Immediate(instr->function()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001826 static const int kAdditionalDelta = 16;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001827 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
1828 Label before_push_delta;
1829 __ bind(&before_push_delta);
1830 __ mov(temp, Immediate(delta));
1831 __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001832 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001833 __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
1834 ASSERT_EQ(kAdditionalDelta,
1835 masm_->SizeOfCodeGeneratedSince(&before_push_delta));
1836 RecordSafepointWithRegisters(
1837 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1838 // Put the result value into the eax slot and restore all registers.
1839 __ mov(Operand(esp, EspIndexForPushAll(eax) * kPointerSize), eax);
1840
1841 __ PopSafepointRegisters();
1842}
1843
1844
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001845static Condition ComputeCompareCondition(Token::Value op) {
1846 switch (op) {
1847 case Token::EQ_STRICT:
1848 case Token::EQ:
1849 return equal;
1850 case Token::LT:
1851 return less;
1852 case Token::GT:
1853 return greater;
1854 case Token::LTE:
1855 return less_equal;
1856 case Token::GTE:
1857 return greater_equal;
1858 default:
1859 UNREACHABLE();
1860 return no_condition;
1861 }
1862}
1863
1864
1865void LCodeGen::DoCmpT(LCmpT* instr) {
1866 Token::Value op = instr->op();
1867
1868 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001869 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001870
1871 Condition condition = ComputeCompareCondition(op);
1872 if (op == Token::GT || op == Token::LTE) {
1873 condition = ReverseCondition(condition);
1874 }
1875 NearLabel true_value, done;
1876 __ test(eax, Operand(eax));
1877 __ j(condition, &true_value);
1878 __ mov(ToRegister(instr->result()), Factory::false_value());
1879 __ jmp(&done);
1880 __ bind(&true_value);
1881 __ mov(ToRegister(instr->result()), Factory::true_value());
1882 __ bind(&done);
1883}
1884
1885
1886void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
1887 Token::Value op = instr->op();
1888 int true_block = chunk_->LookupDestination(instr->true_block_id());
1889 int false_block = chunk_->LookupDestination(instr->false_block_id());
1890
1891 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001892 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001893
1894 // The compare stub expects compare condition and the input operands
1895 // reversed for GT and LTE.
1896 Condition condition = ComputeCompareCondition(op);
1897 if (op == Token::GT || op == Token::LTE) {
1898 condition = ReverseCondition(condition);
1899 }
1900 __ test(eax, Operand(eax));
1901 EmitBranch(true_block, false_block, condition);
1902}
1903
1904
1905void LCodeGen::DoReturn(LReturn* instr) {
1906 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001907 // Preserve the return value on the stack and rely on the runtime call
1908 // to return the value in the same register. We're leaving the code
1909 // managed by the register allocator and tearing down the frame, it's
1910 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001911 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001912 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001913 __ CallRuntime(Runtime::kTraceExit, 1);
1914 }
1915 __ mov(esp, ebp);
1916 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001917 __ Ret((ParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001918}
1919
1920
1921void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
1922 Register result = ToRegister(instr->result());
1923 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
1924 if (instr->hydrogen()->check_hole_value()) {
1925 __ cmp(result, Factory::the_hole_value());
1926 DeoptimizeIf(equal, instr->environment());
1927 }
1928}
1929
1930
1931void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001932 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001933 Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
1934
1935 // If the cell we are storing to contains the hole it could have
1936 // been deleted from the property dictionary. In that case, we need
1937 // to update the property details in the property dictionary to mark
1938 // it as no longer deleted. We deoptimize in that case.
1939 if (instr->hydrogen()->check_hole_value()) {
1940 __ cmp(cell_operand, Factory::the_hole_value());
1941 DeoptimizeIf(equal, instr->environment());
1942 }
1943
1944 // Store the value.
1945 __ mov(cell_operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946}
1947
1948
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001949void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001950 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001951 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001952 __ mov(result, ContextOperand(context, instr->slot_index()));
1953}
1954
1955
1956void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
1957 Register context = ToRegister(instr->context());
1958 Register value = ToRegister(instr->value());
1959 __ mov(ContextOperand(context, instr->slot_index()), value);
1960 if (instr->needs_write_barrier()) {
1961 Register temp = ToRegister(instr->TempAt(0));
1962 int offset = Context::SlotOffset(instr->slot_index());
1963 __ RecordWrite(context, offset, value, temp);
1964 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001965}
1966
1967
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001968void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001969 Register object = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001970 Register result = ToRegister(instr->result());
1971 if (instr->hydrogen()->is_in_object()) {
1972 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
1973 } else {
1974 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
1975 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
1976 }
1977}
1978
1979
1980void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001981 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001982 ASSERT(ToRegister(instr->object()).is(eax));
1983 ASSERT(ToRegister(instr->result()).is(eax));
1984
1985 __ mov(ecx, instr->name());
1986 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1987 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1988}
1989
1990
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001991void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
1992 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001993 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001994 Register result = ToRegister(instr->result());
1995
1996 // Check that the function really is a function.
1997 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
1998 DeoptimizeIf(not_equal, instr->environment());
1999
2000 // Check whether the function has an instance prototype.
2001 NearLabel non_instance;
2002 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2003 1 << Map::kHasNonInstancePrototype);
2004 __ j(not_zero, &non_instance);
2005
2006 // Get the prototype or initial map from the function.
2007 __ mov(result,
2008 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2009
2010 // Check that the function has a prototype or an initial map.
2011 __ cmp(Operand(result), Immediate(Factory::the_hole_value()));
2012 DeoptimizeIf(equal, instr->environment());
2013
2014 // If the function does not have an initial map, we're done.
2015 NearLabel done;
2016 __ CmpObjectType(result, MAP_TYPE, temp);
2017 __ j(not_equal, &done);
2018
2019 // Get the prototype from the initial map.
2020 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
2021 __ jmp(&done);
2022
2023 // Non-instance prototype: Fetch prototype from constructor field
2024 // in the function's map.
2025 __ bind(&non_instance);
2026 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2027
2028 // All done.
2029 __ bind(&done);
2030}
2031
2032
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002033void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002034 Register result = ToRegister(instr->result());
2035 Register input = ToRegister(instr->InputAt(0));
2036 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002037 if (FLAG_debug_code) {
2038 NearLabel done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002039 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002040 Immediate(Factory::fixed_array_map()));
2041 __ j(equal, &done);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002042 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
2043 Immediate(Factory::pixel_array_map()));
2044 __ j(equal, &done);
2045 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002046 Immediate(Factory::fixed_cow_array_map()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002047 __ Check(equal, "Check for fast elements or pixel array failed.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 __ bind(&done);
2049 }
2050}
2051
2052
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002053void LCodeGen::DoLoadPixelArrayExternalPointer(
2054 LLoadPixelArrayExternalPointer* instr) {
2055 Register result = ToRegister(instr->result());
2056 Register input = ToRegister(instr->InputAt(0));
2057 __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
2058}
2059
2060
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002061void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2062 Register arguments = ToRegister(instr->arguments());
2063 Register length = ToRegister(instr->length());
2064 Operand index = ToOperand(instr->index());
2065 Register result = ToRegister(instr->result());
2066
2067 __ sub(length, index);
2068 DeoptimizeIf(below_equal, instr->environment());
2069
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002070 // There are two words between the frame pointer and the last argument.
2071 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002072 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2073}
2074
2075
2076void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
2077 Register elements = ToRegister(instr->elements());
2078 Register key = ToRegister(instr->key());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002079 Register result = ToRegister(instr->result());
2080 ASSERT(result.is(elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002081
2082 // Load the result.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002083 __ mov(result, FieldOperand(elements,
2084 key,
2085 times_pointer_size,
2086 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002087
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002088 // Check for the hole value.
2089 __ cmp(result, Factory::the_hole_value());
2090 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002091}
2092
2093
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002094void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
2095 Register external_elements = ToRegister(instr->external_pointer());
2096 Register key = ToRegister(instr->key());
2097 Register result = ToRegister(instr->result());
2098 ASSERT(result.is(external_elements));
2099
2100 // Load the result.
2101 __ movzx_b(result, Operand(external_elements, key, times_1, 0));
2102}
2103
2104
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002105void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002106 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002107 ASSERT(ToRegister(instr->object()).is(edx));
2108 ASSERT(ToRegister(instr->key()).is(eax));
2109
2110 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
2111 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2112}
2113
2114
2115void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2116 Register result = ToRegister(instr->result());
2117
2118 // Check for arguments adapter frame.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002119 NearLabel done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002120 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2121 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2122 __ cmp(Operand(result),
2123 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2124 __ j(equal, &adapted);
2125
2126 // No arguments adaptor frame.
2127 __ mov(result, Operand(ebp));
2128 __ jmp(&done);
2129
2130 // Arguments adaptor frame present.
2131 __ bind(&adapted);
2132 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2133
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002134 // Result is the frame pointer for the frame if not adapted and for the real
2135 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002136 __ bind(&done);
2137}
2138
2139
2140void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002141 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002142 Register result = ToRegister(instr->result());
2143
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002144 NearLabel done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002146 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002147 __ cmp(ebp, elem);
2148 __ mov(result, Immediate(scope()->num_parameters()));
2149 __ j(equal, &done);
2150
2151 // Arguments adaptor frame present. Get argument length from there.
2152 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2153 __ mov(result, Operand(result,
2154 ArgumentsAdaptorFrameConstants::kLengthOffset));
2155 __ SmiUntag(result);
2156
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002157 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002158 __ bind(&done);
2159}
2160
2161
2162void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2163 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002164 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002165 Register length = ToRegister(instr->length());
2166 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002167 Register scratch = ToRegister(instr->TempAt(0));
2168 ASSERT(receiver.is(eax)); // Used for parameter count.
2169 ASSERT(function.is(edi)); // Required by InvokeFunction.
2170 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002171
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002172 // If the receiver is null or undefined, we have to pass the global object
2173 // as a receiver.
2174 NearLabel global_object, receiver_ok;
2175 __ cmp(receiver, Factory::null_value());
2176 __ j(equal, &global_object);
2177 __ cmp(receiver, Factory::undefined_value());
2178 __ j(equal, &global_object);
2179
2180 // The receiver should be a JS object.
2181 __ test(receiver, Immediate(kSmiTagMask));
2182 DeoptimizeIf(equal, instr->environment());
2183 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch);
2184 DeoptimizeIf(below, instr->environment());
2185 __ jmp(&receiver_ok);
2186
2187 __ bind(&global_object);
2188 // TODO(kmillikin): We have a hydrogen value for the global object. See
2189 // if it's better to use it than to explicitly fetch it from the context
2190 // here.
2191 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2192 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
2193 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002194
2195 // Copy the arguments to this function possibly from the
2196 // adaptor frame below it.
2197 const uint32_t kArgumentsLimit = 1 * KB;
2198 __ cmp(length, kArgumentsLimit);
2199 DeoptimizeIf(above, instr->environment());
2200
2201 __ push(receiver);
2202 __ mov(receiver, length);
2203
2204 // Loop through the arguments pushing them onto the execution
2205 // stack.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002206 NearLabel invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002207 // length is a small non-negative integer, due to the test above.
2208 __ test(length, Operand(length));
2209 __ j(zero, &invoke);
2210 __ bind(&loop);
2211 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2212 __ dec(length);
2213 __ j(not_zero, &loop);
2214
2215 // Invoke the function.
2216 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002217 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2218 LPointerMap* pointers = instr->pointer_map();
2219 LEnvironment* env = instr->deoptimization_environment();
2220 RecordPosition(pointers->position());
2221 RegisterEnvironmentForDeoptimization(env);
2222 SafepointGenerator safepoint_generator(this,
2223 pointers,
2224 env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002225 v8::internal::ParameterCount actual(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002226 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002227}
2228
2229
2230void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002231 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002232 if (argument->IsConstantOperand()) {
2233 __ push(ToImmediate(argument));
2234 } else {
2235 __ push(ToOperand(argument));
2236 }
2237}
2238
2239
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002240void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002241 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002242 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002243}
2244
2245
2246void LCodeGen::DoOuterContext(LOuterContext* instr) {
2247 Register context = ToRegister(instr->context());
2248 Register result = ToRegister(instr->result());
2249 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2250 __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
2251}
2252
2253
2254void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2255 Register context = ToRegister(instr->context());
2256 Register result = ToRegister(instr->result());
2257 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002258}
2259
2260
2261void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002262 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002263 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002264 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002265}
2266
2267
2268void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2269 int arity,
2270 LInstruction* instr) {
2271 // Change context if needed.
2272 bool change_context =
2273 (graph()->info()->closure()->context() != function->context()) ||
2274 scope()->contains_with() ||
2275 (scope()->num_heap_slots() > 0);
2276 if (change_context) {
2277 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002278 } else {
2279 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 }
2281
2282 // Set eax to arguments count if adaption is not needed. Assumes that eax
2283 // is available to write to at this point.
2284 if (!function->NeedsArgumentsAdaption()) {
2285 __ mov(eax, arity);
2286 }
2287
2288 LPointerMap* pointers = instr->pointer_map();
2289 RecordPosition(pointers->position());
2290
2291 // Invoke function.
2292 if (*function == *graph()->info()->closure()) {
2293 __ CallSelf();
2294 } else {
2295 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2296 }
2297
2298 // Setup deoptimization.
2299 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002300}
2301
2302
2303void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2304 ASSERT(ToRegister(instr->result()).is(eax));
2305 __ mov(edi, instr->function());
2306 CallKnownFunction(instr->function(), instr->arity(), instr);
2307}
2308
2309
2310void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002311 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002312 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
2313 Factory::heap_number_map());
2314 DeoptimizeIf(not_equal, instr->environment());
2315
2316 Label done;
2317 Register tmp = input_reg.is(eax) ? ecx : eax;
2318 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2319
2320 // Preserve the value of all registers.
2321 __ PushSafepointRegisters();
2322
2323 Label negative;
2324 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002325 // Check the sign of the argument. If the argument is positive, just
2326 // return it. We do not need to patch the stack since |input| and
2327 // |result| are the same register and |input| will be restored
2328 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002329 __ test(tmp, Immediate(HeapNumber::kSignMask));
2330 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002331 __ jmp(&done);
2332
2333 __ bind(&negative);
2334
2335 Label allocated, slow;
2336 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2337 __ jmp(&allocated);
2338
2339 // Slow case: Call the runtime system to do the number allocation.
2340 __ bind(&slow);
2341
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002342 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
2344 RecordSafepointWithRegisters(
2345 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
2346 // Set the pointer to the new heap number in tmp.
2347 if (!tmp.is(eax)) __ mov(tmp, eax);
2348
2349 // Restore input_reg after call to runtime.
2350 __ mov(input_reg, Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize));
2351
2352 __ bind(&allocated);
2353 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2354 __ and_(tmp2, ~HeapNumber::kSignMask);
2355 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2356 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2357 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002358 __ mov(Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize), tmp);
2359
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002360 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002361 __ PopSafepointRegisters();
2362}
2363
2364
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002365void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2366 Register input_reg = ToRegister(instr->InputAt(0));
2367 __ test(input_reg, Operand(input_reg));
2368 Label is_positive;
2369 __ j(not_sign, &is_positive);
2370 __ neg(input_reg);
2371 __ test(input_reg, Operand(input_reg));
2372 DeoptimizeIf(negative, instr->environment());
2373 __ bind(&is_positive);
2374}
2375
2376
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002377void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2378 // Class for deferred case.
2379 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2380 public:
2381 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2382 LUnaryMathOperation* instr)
2383 : LDeferredCode(codegen), instr_(instr) { }
2384 virtual void Generate() {
2385 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2386 }
2387 private:
2388 LUnaryMathOperation* instr_;
2389 };
2390
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002391 ASSERT(instr->InputAt(0)->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002392 Representation r = instr->hydrogen()->value()->representation();
2393
2394 if (r.IsDouble()) {
2395 XMMRegister scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002396 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002397 __ pxor(scratch, scratch);
2398 __ subsd(scratch, input_reg);
2399 __ pand(input_reg, scratch);
2400 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002401 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002402 } else { // Tagged case.
2403 DeferredMathAbsTaggedHeapNumber* deferred =
2404 new DeferredMathAbsTaggedHeapNumber(this, instr);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002405 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002406 // Smi check.
2407 __ test(input_reg, Immediate(kSmiTagMask));
2408 __ j(not_zero, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002409 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002410 __ bind(deferred->exit());
2411 }
2412}
2413
2414
2415void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2416 XMMRegister xmm_scratch = xmm0;
2417 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002418 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002419 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2420 __ ucomisd(input_reg, xmm_scratch);
2421
2422 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2423 DeoptimizeIf(below_equal, instr->environment());
2424 } else {
2425 DeoptimizeIf(below, instr->environment());
2426 }
2427
2428 // Use truncating instruction (OK because input is positive).
2429 __ cvttsd2si(output_reg, Operand(input_reg));
2430
2431 // Overflow is signalled with minint.
2432 __ cmp(output_reg, 0x80000000u);
2433 DeoptimizeIf(equal, instr->environment());
2434}
2435
2436
2437void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2438 XMMRegister xmm_scratch = xmm0;
2439 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002440 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002441
2442 // xmm_scratch = 0.5
2443 ExternalReference one_half = ExternalReference::address_of_one_half();
2444 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
2445
2446 // input = input + 0.5
2447 __ addsd(input_reg, xmm_scratch);
2448
2449 // We need to return -0 for the input range [-0.5, 0[, otherwise
2450 // compute Math.floor(value + 0.5).
2451 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2452 __ ucomisd(input_reg, xmm_scratch);
2453 DeoptimizeIf(below_equal, instr->environment());
2454 } else {
2455 // If we don't need to bailout on -0, we check only bailout
2456 // on negative inputs.
2457 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2458 __ ucomisd(input_reg, xmm_scratch);
2459 DeoptimizeIf(below, instr->environment());
2460 }
2461
2462 // Compute Math.floor(value + 0.5).
2463 // Use truncating instruction (OK because input is positive).
2464 __ cvttsd2si(output_reg, Operand(input_reg));
2465
2466 // Overflow is signalled with minint.
2467 __ cmp(output_reg, 0x80000000u);
2468 DeoptimizeIf(equal, instr->environment());
2469}
2470
2471
2472void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002473 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002474 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2475 __ sqrtsd(input_reg, input_reg);
2476}
2477
2478
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002479void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2480 XMMRegister xmm_scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002481 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002482 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2483 ExternalReference negative_infinity =
2484 ExternalReference::address_of_negative_infinity();
2485 __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity));
2486 __ ucomisd(xmm_scratch, input_reg);
2487 DeoptimizeIf(equal, instr->environment());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002488 __ xorpd(xmm_scratch, xmm_scratch);
2489 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002490 __ sqrtsd(input_reg, input_reg);
2491}
2492
2493
2494void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002495 LOperand* left = instr->InputAt(0);
2496 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002497 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2498 Representation exponent_type = instr->hydrogen()->right()->representation();
2499 if (exponent_type.IsDouble()) {
2500 // It is safe to use ebx directly since the instruction is marked
2501 // as a call.
2502 __ PrepareCallCFunction(4, ebx);
2503 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2504 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
2505 __ CallCFunction(ExternalReference::power_double_double_function(), 4);
2506 } else if (exponent_type.IsInteger32()) {
2507 // It is safe to use ebx directly since the instruction is marked
2508 // as a call.
2509 ASSERT(!ToRegister(right).is(ebx));
2510 __ PrepareCallCFunction(4, ebx);
2511 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2512 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
2513 __ CallCFunction(ExternalReference::power_double_int_function(), 4);
2514 } else {
2515 ASSERT(exponent_type.IsTagged());
2516 CpuFeatures::Scope scope(SSE2);
2517 Register right_reg = ToRegister(right);
2518
2519 Label non_smi, call;
2520 __ test(right_reg, Immediate(kSmiTagMask));
2521 __ j(not_zero, &non_smi);
2522 __ SmiUntag(right_reg);
2523 __ cvtsi2sd(result_reg, Operand(right_reg));
2524 __ jmp(&call);
2525
2526 __ bind(&non_smi);
2527 // It is safe to use ebx directly since the instruction is marked
2528 // as a call.
2529 ASSERT(!right_reg.is(ebx));
2530 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
2531 DeoptimizeIf(not_equal, instr->environment());
2532 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
2533
2534 __ bind(&call);
2535 __ PrepareCallCFunction(4, ebx);
2536 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2537 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
2538 __ CallCFunction(ExternalReference::power_double_double_function(), 4);
2539 }
2540
2541 // Return value is in st(0) on ia32.
2542 // Store it into the (fixed) result register.
2543 __ sub(Operand(esp), Immediate(kDoubleSize));
2544 __ fstp_d(Operand(esp, 0));
2545 __ movdbl(result_reg, Operand(esp, 0));
2546 __ add(Operand(esp), Immediate(kDoubleSize));
2547}
2548
2549
2550void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
2551 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002552 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2553 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002554 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002555}
2556
2557
2558void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
2559 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2560 TranscendentalCacheStub stub(TranscendentalCache::COS,
2561 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002562 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002563}
2564
2565
2566void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
2567 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2568 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2569 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002570 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002571}
2572
2573
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002574void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
2575 switch (instr->op()) {
2576 case kMathAbs:
2577 DoMathAbs(instr);
2578 break;
2579 case kMathFloor:
2580 DoMathFloor(instr);
2581 break;
2582 case kMathRound:
2583 DoMathRound(instr);
2584 break;
2585 case kMathSqrt:
2586 DoMathSqrt(instr);
2587 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002588 case kMathPowHalf:
2589 DoMathPowHalf(instr);
2590 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00002591 case kMathCos:
2592 DoMathCos(instr);
2593 break;
2594 case kMathSin:
2595 DoMathSin(instr);
2596 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002597 case kMathLog:
2598 DoMathLog(instr);
2599 break;
2600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002601 default:
2602 UNREACHABLE();
2603 }
2604}
2605
2606
2607void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002608 ASSERT(ToRegister(instr->context()).is(esi));
2609 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002610 ASSERT(ToRegister(instr->result()).is(eax));
2611
2612 int arity = instr->arity();
2613 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
2614 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002615}
2616
2617
2618void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002619 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002620 ASSERT(ToRegister(instr->result()).is(eax));
2621
2622 int arity = instr->arity();
2623 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
2624 __ mov(ecx, instr->name());
2625 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002626}
2627
2628
2629void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002630 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002631 ASSERT(ToRegister(instr->result()).is(eax));
2632
2633 int arity = instr->arity();
2634 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
2635 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2636 __ Drop(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002637}
2638
2639
2640void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002641 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002642 ASSERT(ToRegister(instr->result()).is(eax));
2643
2644 int arity = instr->arity();
2645 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
2646 __ mov(ecx, instr->name());
2647 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002648}
2649
2650
2651void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
2652 ASSERT(ToRegister(instr->result()).is(eax));
2653 __ mov(edi, instr->target());
2654 CallKnownFunction(instr->target(), instr->arity(), instr);
2655}
2656
2657
2658void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002659 ASSERT(ToRegister(instr->context()).is(esi));
2660 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002661 ASSERT(ToRegister(instr->result()).is(eax));
2662
2663 Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
2664 __ Set(eax, Immediate(instr->arity()));
2665 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
2666}
2667
2668
2669void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002670 CallRuntime(instr->function(), instr->arity(), instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002671}
2672
2673
2674void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
2675 Register object = ToRegister(instr->object());
2676 Register value = ToRegister(instr->value());
2677 int offset = instr->offset();
2678
2679 if (!instr->transition().is_null()) {
2680 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
2681 }
2682
2683 // Do the store.
2684 if (instr->is_in_object()) {
2685 __ mov(FieldOperand(object, offset), value);
2686 if (instr->needs_write_barrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002687 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002688 // Update the write barrier for the object for in-object properties.
2689 __ RecordWrite(object, offset, value, temp);
2690 }
2691 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002692 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002693 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
2694 __ mov(FieldOperand(temp, offset), value);
2695 if (instr->needs_write_barrier()) {
2696 // Update the write barrier for the properties array.
2697 // object is used as a scratch register.
2698 __ RecordWrite(temp, offset, value, object);
2699 }
2700 }
2701}
2702
2703
2704void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002705 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002706 ASSERT(ToRegister(instr->object()).is(edx));
2707 ASSERT(ToRegister(instr->value()).is(eax));
2708
2709 __ mov(ecx, instr->name());
2710 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
2711 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2712}
2713
2714
2715void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
2716 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
2717 DeoptimizeIf(above_equal, instr->environment());
2718}
2719
2720
2721void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
2722 Register value = ToRegister(instr->value());
2723 Register elements = ToRegister(instr->object());
2724 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
2725
2726 // Do the store.
2727 if (instr->key()->IsConstantOperand()) {
2728 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
2729 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
2730 int offset =
2731 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
2732 __ mov(FieldOperand(elements, offset), value);
2733 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002734 __ mov(FieldOperand(elements,
2735 key,
2736 times_pointer_size,
2737 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002738 value);
2739 }
2740
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002741 if (instr->hydrogen()->NeedsWriteBarrier()) {
2742 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002743 __ lea(key,
2744 FieldOperand(elements,
2745 key,
2746 times_pointer_size,
2747 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002748 __ RecordWrite(elements, key, value);
2749 }
2750}
2751
2752
2753void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002754 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002755 ASSERT(ToRegister(instr->object()).is(edx));
2756 ASSERT(ToRegister(instr->key()).is(ecx));
2757 ASSERT(ToRegister(instr->value()).is(eax));
2758
2759 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
2760 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2761}
2762
2763
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002764void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
2765 class DeferredStringCharCodeAt: public LDeferredCode {
2766 public:
2767 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
2768 : LDeferredCode(codegen), instr_(instr) { }
2769 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
2770 private:
2771 LStringCharCodeAt* instr_;
2772 };
2773
2774 Register string = ToRegister(instr->string());
2775 Register index = no_reg;
2776 int const_index = -1;
2777 if (instr->index()->IsConstantOperand()) {
2778 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2779 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
2780 if (!Smi::IsValid(const_index)) {
2781 // Guaranteed to be out of bounds because of the assert above.
2782 // So the bounds check that must dominate this instruction must
2783 // have deoptimized already.
2784 if (FLAG_debug_code) {
2785 __ Abort("StringCharCodeAt: out of bounds index.");
2786 }
2787 // No code needs to be generated.
2788 return;
2789 }
2790 } else {
2791 index = ToRegister(instr->index());
2792 }
2793 Register result = ToRegister(instr->result());
2794
2795 DeferredStringCharCodeAt* deferred =
2796 new DeferredStringCharCodeAt(this, instr);
2797
2798 NearLabel flat_string, ascii_string, done;
2799
2800 // Fetch the instance type of the receiver into result register.
2801 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
2802 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
2803
2804 // We need special handling for non-flat strings.
2805 STATIC_ASSERT(kSeqStringTag == 0);
2806 __ test(result, Immediate(kStringRepresentationMask));
2807 __ j(zero, &flat_string);
2808
2809 // Handle non-flat strings.
2810 __ test(result, Immediate(kIsConsStringMask));
2811 __ j(zero, deferred->entry());
2812
2813 // ConsString.
2814 // Check whether the right hand side is the empty string (i.e. if
2815 // this is really a flat string in a cons string). If that is not
2816 // the case we would rather go to the runtime system now to flatten
2817 // the string.
2818 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
2819 Immediate(Factory::empty_string()));
2820 __ j(not_equal, deferred->entry());
2821 // Get the first of the two strings and load its instance type.
2822 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
2823 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
2824 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
2825 // If the first cons component is also non-flat, then go to runtime.
2826 STATIC_ASSERT(kSeqStringTag == 0);
2827 __ test(result, Immediate(kStringRepresentationMask));
2828 __ j(not_zero, deferred->entry());
2829
2830 // Check for 1-byte or 2-byte string.
2831 __ bind(&flat_string);
2832 STATIC_ASSERT(kAsciiStringTag != 0);
2833 __ test(result, Immediate(kStringEncodingMask));
2834 __ j(not_zero, &ascii_string);
2835
2836 // 2-byte string.
2837 // Load the 2-byte character code into the result register.
2838 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2839 if (instr->index()->IsConstantOperand()) {
2840 __ movzx_w(result,
2841 FieldOperand(string,
2842 SeqTwoByteString::kHeaderSize + 2 * const_index));
2843 } else {
2844 __ movzx_w(result, FieldOperand(string,
2845 index,
2846 times_2,
2847 SeqTwoByteString::kHeaderSize));
2848 }
2849 __ jmp(&done);
2850
2851 // ASCII string.
2852 // Load the byte into the result register.
2853 __ bind(&ascii_string);
2854 if (instr->index()->IsConstantOperand()) {
2855 __ movzx_b(result, FieldOperand(string,
2856 SeqAsciiString::kHeaderSize + const_index));
2857 } else {
2858 __ movzx_b(result, FieldOperand(string,
2859 index,
2860 times_1,
2861 SeqAsciiString::kHeaderSize));
2862 }
2863 __ bind(&done);
2864 __ bind(deferred->exit());
2865}
2866
2867
2868void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
2869 Register string = ToRegister(instr->string());
2870 Register result = ToRegister(instr->result());
2871
2872 // TODO(3095996): Get rid of this. For now, we need to make the
2873 // result register contain a valid pointer because it is already
2874 // contained in the register pointer map.
2875 __ Set(result, Immediate(0));
2876
2877 __ PushSafepointRegisters();
2878 __ push(string);
2879 // Push the index as a smi. This is safe because of the checks in
2880 // DoStringCharCodeAt above.
2881 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
2882 if (instr->index()->IsConstantOperand()) {
2883 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2884 __ push(Immediate(Smi::FromInt(const_index)));
2885 } else {
2886 Register index = ToRegister(instr->index());
2887 __ SmiTag(index);
2888 __ push(index);
2889 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002890 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002891 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
2892 RecordSafepointWithRegisters(
2893 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
2894 if (FLAG_debug_code) {
2895 __ AbortIfNotSmi(eax);
2896 }
2897 __ SmiUntag(eax);
2898 __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax);
2899 __ PopSafepointRegisters();
2900}
2901
2902
2903void LCodeGen::DoStringLength(LStringLength* instr) {
2904 Register string = ToRegister(instr->string());
2905 Register result = ToRegister(instr->result());
2906 __ mov(result, FieldOperand(string, String::kLengthOffset));
2907}
2908
2909
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002910void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002911 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002912 ASSERT(input->IsRegister() || input->IsStackSlot());
2913 LOperand* output = instr->result();
2914 ASSERT(output->IsDoubleRegister());
2915 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
2916}
2917
2918
2919void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
2920 class DeferredNumberTagI: public LDeferredCode {
2921 public:
2922 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
2923 : LDeferredCode(codegen), instr_(instr) { }
2924 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
2925 private:
2926 LNumberTagI* instr_;
2927 };
2928
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002929 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002930 ASSERT(input->IsRegister() && input->Equals(instr->result()));
2931 Register reg = ToRegister(input);
2932
2933 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
2934 __ SmiTag(reg);
2935 __ j(overflow, deferred->entry());
2936 __ bind(deferred->exit());
2937}
2938
2939
2940void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
2941 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002942 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002943 Register tmp = reg.is(eax) ? ecx : eax;
2944
2945 // Preserve the value of all registers.
2946 __ PushSafepointRegisters();
2947
2948 // There was overflow, so bits 30 and 31 of the original integer
2949 // disagree. Try to allocate a heap number in new space and store
2950 // the value in there. If that fails, call the runtime system.
2951 NearLabel done;
2952 __ SmiUntag(reg);
2953 __ xor_(reg, 0x80000000);
2954 __ cvtsi2sd(xmm0, Operand(reg));
2955 if (FLAG_inline_new) {
2956 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
2957 __ jmp(&done);
2958 }
2959
2960 // Slow case: Call the runtime system to do the number allocation.
2961 __ bind(&slow);
2962
2963 // TODO(3095996): Put a valid pointer value in the stack slot where the result
2964 // register is stored, as this register is in the pointer map, but contains an
2965 // integer value.
2966 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), Immediate(0));
2967
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002968 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002969 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
2970 RecordSafepointWithRegisters(
2971 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
2972 if (!reg.is(eax)) __ mov(reg, eax);
2973
2974 // Done. Put the value in xmm0 into the value of the allocated heap
2975 // number.
2976 __ bind(&done);
2977 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
2978 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), reg);
2979 __ PopSafepointRegisters();
2980}
2981
2982
2983void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
2984 class DeferredNumberTagD: public LDeferredCode {
2985 public:
2986 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
2987 : LDeferredCode(codegen), instr_(instr) { }
2988 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
2989 private:
2990 LNumberTagD* instr_;
2991 };
2992
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002993 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002994 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002995 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002996
2997 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
2998 if (FLAG_inline_new) {
2999 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3000 } else {
3001 __ jmp(deferred->entry());
3002 }
3003 __ bind(deferred->exit());
3004 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3005}
3006
3007
3008void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3009 // TODO(3095996): Get rid of this. For now, we need to make the
3010 // result register contain a valid pointer because it is already
3011 // contained in the register pointer map.
3012 Register reg = ToRegister(instr->result());
3013 __ Set(reg, Immediate(0));
3014
3015 __ PushSafepointRegisters();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003016 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003017 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3018 RecordSafepointWithRegisters(
3019 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
3020 __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), eax);
3021 __ PopSafepointRegisters();
3022}
3023
3024
3025void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003026 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003027 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3028 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3029 __ SmiTag(ToRegister(input));
3030}
3031
3032
3033void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003034 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003035 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3036 if (instr->needs_check()) {
3037 __ test(ToRegister(input), Immediate(kSmiTagMask));
3038 DeoptimizeIf(not_zero, instr->environment());
3039 }
3040 __ SmiUntag(ToRegister(input));
3041}
3042
3043
3044void LCodeGen::EmitNumberUntagD(Register input_reg,
3045 XMMRegister result_reg,
3046 LEnvironment* env) {
3047 NearLabel load_smi, heap_number, done;
3048
3049 // Smi check.
3050 __ test(input_reg, Immediate(kSmiTagMask));
3051 __ j(zero, &load_smi, not_taken);
3052
3053 // Heap number map check.
3054 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3055 Factory::heap_number_map());
3056 __ j(equal, &heap_number);
3057
3058 __ cmp(input_reg, Factory::undefined_value());
3059 DeoptimizeIf(not_equal, env);
3060
3061 // Convert undefined to NaN.
3062 __ push(input_reg);
3063 __ mov(input_reg, Factory::nan_value());
3064 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3065 __ pop(input_reg);
3066 __ jmp(&done);
3067
3068 // Heap number to XMM conversion.
3069 __ bind(&heap_number);
3070 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3071 __ jmp(&done);
3072
3073 // Smi to XMM conversion
3074 __ bind(&load_smi);
3075 __ SmiUntag(input_reg); // Untag smi before converting to float.
3076 __ cvtsi2sd(result_reg, Operand(input_reg));
3077 __ SmiTag(input_reg); // Retag smi.
3078 __ bind(&done);
3079}
3080
3081
3082class DeferredTaggedToI: public LDeferredCode {
3083 public:
3084 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3085 : LDeferredCode(codegen), instr_(instr) { }
3086 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3087 private:
3088 LTaggedToI* instr_;
3089};
3090
3091
3092void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
3093 NearLabel done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003094 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095
3096 // Heap number map check.
3097 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3098 Factory::heap_number_map());
3099
3100 if (instr->truncating()) {
3101 __ j(equal, &heap_number);
3102 // Check for undefined. Undefined is converted to zero for truncating
3103 // conversions.
3104 __ cmp(input_reg, Factory::undefined_value());
3105 DeoptimizeIf(not_equal, instr->environment());
3106 __ mov(input_reg, 0);
3107 __ jmp(&done);
3108
3109 __ bind(&heap_number);
3110 if (CpuFeatures::IsSupported(SSE3)) {
3111 CpuFeatures::Scope scope(SSE3);
3112 NearLabel convert;
3113 // Use more powerful conversion when sse3 is available.
3114 // Load x87 register with heap number.
3115 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3116 // Get exponent alone and check for too-big exponent.
3117 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3118 __ and_(input_reg, HeapNumber::kExponentMask);
3119 const uint32_t kTooBigExponent =
3120 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3121 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
3122 __ j(less, &convert);
3123 // Pop FPU stack before deoptimizing.
3124 __ ffree(0);
3125 __ fincstp();
3126 DeoptimizeIf(no_condition, instr->environment());
3127
3128 // Reserve space for 64 bit answer.
3129 __ bind(&convert);
3130 __ sub(Operand(esp), Immediate(kDoubleSize));
3131 // Do conversion, which cannot fail because we checked the exponent.
3132 __ fisttp_d(Operand(esp, 0));
3133 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3134 __ add(Operand(esp), Immediate(kDoubleSize));
3135 } else {
3136 NearLabel deopt;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003137 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003138 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3139 __ cvttsd2si(input_reg, Operand(xmm0));
3140 __ cmp(input_reg, 0x80000000u);
3141 __ j(not_equal, &done);
3142 // Check if the input was 0x8000000 (kMinInt).
3143 // If no, then we got an overflow and we deoptimize.
3144 ExternalReference min_int = ExternalReference::address_of_min_int();
3145 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3146 __ ucomisd(xmm_temp, xmm0);
3147 DeoptimizeIf(not_equal, instr->environment());
3148 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3149 }
3150 } else {
3151 // Deoptimize if we don't have a heap number.
3152 DeoptimizeIf(not_equal, instr->environment());
3153
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003154 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003155 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3156 __ cvttsd2si(input_reg, Operand(xmm0));
3157 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3158 __ ucomisd(xmm0, xmm_temp);
3159 DeoptimizeIf(not_equal, instr->environment());
3160 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3161 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3162 __ test(input_reg, Operand(input_reg));
3163 __ j(not_zero, &done);
3164 __ movmskpd(input_reg, xmm0);
3165 __ and_(input_reg, 1);
3166 DeoptimizeIf(not_zero, instr->environment());
3167 }
3168 }
3169 __ bind(&done);
3170}
3171
3172
3173void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003174 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003175 ASSERT(input->IsRegister());
3176 ASSERT(input->Equals(instr->result()));
3177
3178 Register input_reg = ToRegister(input);
3179
3180 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3181
3182 // Smi check.
3183 __ test(input_reg, Immediate(kSmiTagMask));
3184 __ j(not_zero, deferred->entry());
3185
3186 // Smi to int32 conversion
3187 __ SmiUntag(input_reg); // Untag smi.
3188
3189 __ bind(deferred->exit());
3190}
3191
3192
3193void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003194 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003195 ASSERT(input->IsRegister());
3196 LOperand* result = instr->result();
3197 ASSERT(result->IsDoubleRegister());
3198
3199 Register input_reg = ToRegister(input);
3200 XMMRegister result_reg = ToDoubleRegister(result);
3201
3202 EmitNumberUntagD(input_reg, result_reg, instr->environment());
3203}
3204
3205
3206void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003207 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003208 ASSERT(input->IsDoubleRegister());
3209 LOperand* result = instr->result();
3210 ASSERT(result->IsRegister());
3211
3212 XMMRegister input_reg = ToDoubleRegister(input);
3213 Register result_reg = ToRegister(result);
3214
3215 if (instr->truncating()) {
3216 // Performs a truncating conversion of a floating point number as used by
3217 // the JS bitwise operations.
3218 __ cvttsd2si(result_reg, Operand(input_reg));
3219 __ cmp(result_reg, 0x80000000u);
3220 if (CpuFeatures::IsSupported(SSE3)) {
3221 // This will deoptimize if the exponent of the input in out of range.
3222 CpuFeatures::Scope scope(SSE3);
3223 NearLabel convert, done;
3224 __ j(not_equal, &done);
3225 __ sub(Operand(esp), Immediate(kDoubleSize));
3226 __ movdbl(Operand(esp, 0), input_reg);
3227 // Get exponent alone and check for too-big exponent.
3228 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3229 __ and_(result_reg, HeapNumber::kExponentMask);
3230 const uint32_t kTooBigExponent =
3231 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3232 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
3233 __ j(less, &convert);
3234 __ add(Operand(esp), Immediate(kDoubleSize));
3235 DeoptimizeIf(no_condition, instr->environment());
3236 __ bind(&convert);
3237 // Do conversion, which cannot fail because we checked the exponent.
3238 __ fld_d(Operand(esp, 0));
3239 __ fisttp_d(Operand(esp, 0));
3240 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3241 __ add(Operand(esp), Immediate(kDoubleSize));
3242 __ bind(&done);
3243 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003244 NearLabel done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003245 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003246 XMMRegister xmm_scratch = xmm0;
3247
3248 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3249 // manual conversion.
3250 __ j(not_equal, &done);
3251
3252 // Get high 32 bits of the input in result_reg and temp_reg.
3253 __ pshufd(xmm_scratch, input_reg, 1);
3254 __ movd(Operand(temp_reg), xmm_scratch);
3255 __ mov(result_reg, temp_reg);
3256
3257 // Prepare negation mask in temp_reg.
3258 __ sar(temp_reg, kBitsPerInt - 1);
3259
3260 // Extract the exponent from result_reg and subtract adjusted
3261 // bias from it. The adjustment is selected in a way such that
3262 // when the difference is zero, the answer is in the low 32 bits
3263 // of the input, otherwise a shift has to be performed.
3264 __ shr(result_reg, HeapNumber::kExponentShift);
3265 __ and_(result_reg,
3266 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3267 __ sub(Operand(result_reg),
3268 Immediate(HeapNumber::kExponentBias +
3269 HeapNumber::kExponentBits +
3270 HeapNumber::kMantissaBits));
3271 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3272 // special exponents.
3273 DeoptimizeIf(greater, instr->environment());
3274
3275 // Zero out the sign and the exponent in the input (by shifting
3276 // it to the left) and restore the implicit mantissa bit,
3277 // i.e. convert the input to unsigned int64 shifted left by
3278 // kExponentBits.
3279 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3280 // Minus zero has the most significant bit set and the other
3281 // bits cleared.
3282 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3283 __ psllq(input_reg, HeapNumber::kExponentBits);
3284 __ por(input_reg, xmm_scratch);
3285
3286 // Get the amount to shift the input right in xmm_scratch.
3287 __ neg(result_reg);
3288 __ movd(xmm_scratch, Operand(result_reg));
3289
3290 // Shift the input right and extract low 32 bits.
3291 __ psrlq(input_reg, xmm_scratch);
3292 __ movd(Operand(result_reg), input_reg);
3293
3294 // Use the prepared mask in temp_reg to negate the result if necessary.
3295 __ xor_(result_reg, Operand(temp_reg));
3296 __ sub(result_reg, Operand(temp_reg));
3297 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298 }
3299 } else {
3300 NearLabel done;
3301 __ cvttsd2si(result_reg, Operand(input_reg));
3302 __ cvtsi2sd(xmm0, Operand(result_reg));
3303 __ ucomisd(xmm0, input_reg);
3304 DeoptimizeIf(not_equal, instr->environment());
3305 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3306 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3307 // The integer converted back is equal to the original. We
3308 // only have to test if we got -0 as an input.
3309 __ test(result_reg, Operand(result_reg));
3310 __ j(not_zero, &done);
3311 __ movmskpd(result_reg, input_reg);
3312 // Bit 0 contains the sign of the double in input_reg.
3313 // If input was positive, we are ok and return 0, otherwise
3314 // deoptimize.
3315 __ and_(result_reg, 1);
3316 DeoptimizeIf(not_zero, instr->environment());
3317 }
3318 __ bind(&done);
3319 }
3320}
3321
3322
3323void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003324 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003325 ASSERT(input->IsRegister());
3326 __ test(ToRegister(input), Immediate(kSmiTagMask));
3327 DeoptimizeIf(instr->condition(), instr->environment());
3328}
3329
3330
3331void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003332 Register input = ToRegister(instr->InputAt(0));
3333 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003334 InstanceType first = instr->hydrogen()->first();
3335 InstanceType last = instr->hydrogen()->last();
3336
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003337 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003338
3339 // If there is only one type in the interval check for equality.
3340 if (first == last) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003341 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3342 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003343 DeoptimizeIf(not_equal, instr->environment());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003344 } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
3345 // String has a dedicated bit in instance type.
3346 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), kIsNotStringMask);
3347 DeoptimizeIf(not_zero, instr->environment());
3348 } else {
3349 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3350 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351 DeoptimizeIf(below, instr->environment());
3352 // Omit check for the last type.
3353 if (last != LAST_TYPE) {
3354 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3355 static_cast<int8_t>(last));
3356 DeoptimizeIf(above, instr->environment());
3357 }
3358 }
3359}
3360
3361
3362void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003363 ASSERT(instr->InputAt(0)->IsRegister());
3364 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003365 __ cmp(reg, instr->hydrogen()->target());
3366 DeoptimizeIf(not_equal, instr->environment());
3367}
3368
3369
3370void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003371 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003372 ASSERT(input->IsRegister());
3373 Register reg = ToRegister(input);
3374 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3375 instr->hydrogen()->map());
3376 DeoptimizeIf(not_equal, instr->environment());
3377}
3378
3379
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003380void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
3381 if (Heap::InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003382 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003383 Factory::NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003384 __ mov(result, Operand::Cell(cell));
3385 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003386 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003387 }
3388}
3389
3390
3391void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003392 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003393
3394 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003395 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003396
3397 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003398 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003399
3400 // Check prototype maps up to the holder.
3401 while (!current_prototype.is_identical_to(holder)) {
3402 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3403 Handle<Map>(current_prototype->map()));
3404 DeoptimizeIf(not_equal, instr->environment());
3405 current_prototype =
3406 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3407 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003408 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003409 }
3410
3411 // Check the holder map.
3412 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3413 Handle<Map>(current_prototype->map()));
3414 DeoptimizeIf(not_equal, instr->environment());
3415}
3416
3417
3418void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
3419 // Setup the parameters to the stub/runtime call.
3420 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3421 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3422 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3423 __ push(Immediate(instr->hydrogen()->constant_elements()));
3424
3425 // Pick the right runtime function or stub to call.
3426 int length = instr->hydrogen()->length();
3427 if (instr->hydrogen()->IsCopyOnWrite()) {
3428 ASSERT(instr->hydrogen()->depth() == 1);
3429 FastCloneShallowArrayStub::Mode mode =
3430 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
3431 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003432 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003433 } else if (instr->hydrogen()->depth() > 1) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003434 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003435 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003436 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003437 } else {
3438 FastCloneShallowArrayStub::Mode mode =
3439 FastCloneShallowArrayStub::CLONE_ELEMENTS;
3440 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003441 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003442 }
3443}
3444
3445
3446void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003447 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003448 // Setup the parameters to the stub/runtime call.
3449 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3450 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3451 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3452 __ push(Immediate(instr->hydrogen()->constant_properties()));
3453 __ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
3454
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003455 // Pick the right runtime function to call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003456 if (instr->hydrogen()->depth() > 1) {
3457 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
3458 } else {
3459 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
3460 }
3461}
3462
3463
3464void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
3465 NearLabel materialized;
3466 // Registers will be used as follows:
3467 // edi = JS function.
3468 // ecx = literals array.
3469 // ebx = regexp literal.
3470 // eax = regexp literal clone.
3471 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3472 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
3473 int literal_offset = FixedArray::kHeaderSize +
3474 instr->hydrogen()->literal_index() * kPointerSize;
3475 __ mov(ebx, FieldOperand(ecx, literal_offset));
3476 __ cmp(ebx, Factory::undefined_value());
3477 __ j(not_equal, &materialized);
3478
3479 // Create regexp literal using runtime function
3480 // Result will be in eax.
3481 __ push(ecx);
3482 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3483 __ push(Immediate(instr->hydrogen()->pattern()));
3484 __ push(Immediate(instr->hydrogen()->flags()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003485 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003486 __ mov(ebx, eax);
3487
3488 __ bind(&materialized);
3489 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
3490 Label allocated, runtime_allocate;
3491 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
3492 __ jmp(&allocated);
3493
3494 __ bind(&runtime_allocate);
3495 __ push(ebx);
3496 __ push(Immediate(Smi::FromInt(size)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003497 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003498 __ pop(ebx);
3499
3500 __ bind(&allocated);
3501 // Copy the content into the newly allocated memory.
3502 // (Unroll copy loop once for better throughput).
3503 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
3504 __ mov(edx, FieldOperand(ebx, i));
3505 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
3506 __ mov(FieldOperand(eax, i), edx);
3507 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
3508 }
3509 if ((size % (2 * kPointerSize)) != 0) {
3510 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
3511 __ mov(FieldOperand(eax, size - kPointerSize), edx);
3512 }
3513}
3514
3515
3516void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
3517 // Use the fast case closure allocation code that allocates in new
3518 // space for nested functions that don't need literals cloning.
3519 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003520 bool pretenure = instr->hydrogen()->pretenure();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003521 if (shared_info->num_literals() == 0 && !pretenure) {
3522 FastNewClosureStub stub;
3523 __ push(Immediate(shared_info));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003524 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003525 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003526 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003527 __ push(Immediate(shared_info));
3528 __ push(Immediate(pretenure
3529 ? Factory::true_value()
3530 : Factory::false_value()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003531 CallRuntime(Runtime::kNewClosure, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003532 }
3533}
3534
3535
3536void LCodeGen::DoTypeof(LTypeof* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003537 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003538 if (input->IsConstantOperand()) {
3539 __ push(ToImmediate(input));
3540 } else {
3541 __ push(ToOperand(input));
3542 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003543 CallRuntime(Runtime::kTypeof, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003544}
3545
3546
3547void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003548 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003549 Register result = ToRegister(instr->result());
3550 Label true_label;
3551 Label false_label;
3552 NearLabel done;
3553
3554 Condition final_branch_condition = EmitTypeofIs(&true_label,
3555 &false_label,
3556 input,
3557 instr->type_literal());
3558 __ j(final_branch_condition, &true_label);
3559 __ bind(&false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003560 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003561 __ jmp(&done);
3562
3563 __ bind(&true_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003564 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003565
3566 __ bind(&done);
3567}
3568
3569
3570void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003571 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003572 int true_block = chunk_->LookupDestination(instr->true_block_id());
3573 int false_block = chunk_->LookupDestination(instr->false_block_id());
3574 Label* true_label = chunk_->GetAssemblyLabel(true_block);
3575 Label* false_label = chunk_->GetAssemblyLabel(false_block);
3576
3577 Condition final_branch_condition = EmitTypeofIs(true_label,
3578 false_label,
3579 input,
3580 instr->type_literal());
3581
3582 EmitBranch(true_block, false_block, final_branch_condition);
3583}
3584
3585
3586Condition LCodeGen::EmitTypeofIs(Label* true_label,
3587 Label* false_label,
3588 Register input,
3589 Handle<String> type_name) {
3590 Condition final_branch_condition = no_condition;
3591 if (type_name->Equals(Heap::number_symbol())) {
3592 __ test(input, Immediate(kSmiTagMask));
3593 __ j(zero, true_label);
3594 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
3595 Factory::heap_number_map());
3596 final_branch_condition = equal;
3597
3598 } else if (type_name->Equals(Heap::string_symbol())) {
3599 __ test(input, Immediate(kSmiTagMask));
3600 __ j(zero, false_label);
3601 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
3602 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3603 1 << Map::kIsUndetectable);
3604 __ j(not_zero, false_label);
3605 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
3606 final_branch_condition = below;
3607
3608 } else if (type_name->Equals(Heap::boolean_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003609 __ cmp(input, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003610 __ j(equal, true_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003611 __ cmp(input, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003612 final_branch_condition = equal;
3613
3614 } else if (type_name->Equals(Heap::undefined_symbol())) {
3615 __ cmp(input, Factory::undefined_value());
3616 __ j(equal, true_label);
3617 __ test(input, Immediate(kSmiTagMask));
3618 __ j(zero, false_label);
3619 // Check for undetectable objects => true.
3620 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
3621 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3622 1 << Map::kIsUndetectable);
3623 final_branch_condition = not_zero;
3624
3625 } else if (type_name->Equals(Heap::function_symbol())) {
3626 __ test(input, Immediate(kSmiTagMask));
3627 __ j(zero, false_label);
3628 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
3629 __ j(equal, true_label);
3630 // Regular expressions => 'function' (they are callable).
3631 __ CmpInstanceType(input, JS_REGEXP_TYPE);
3632 final_branch_condition = equal;
3633
3634 } else if (type_name->Equals(Heap::object_symbol())) {
3635 __ test(input, Immediate(kSmiTagMask));
3636 __ j(zero, false_label);
3637 __ cmp(input, Factory::null_value());
3638 __ j(equal, true_label);
3639 // Regular expressions => 'function', not 'object'.
3640 __ CmpObjectType(input, JS_REGEXP_TYPE, input);
3641 __ j(equal, false_label);
3642 // Check for undetectable objects => false.
3643 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3644 1 << Map::kIsUndetectable);
3645 __ j(not_zero, false_label);
3646 // Check for JS objects => true.
3647 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
3648 __ j(below, false_label);
3649 __ CmpInstanceType(input, LAST_JS_OBJECT_TYPE);
3650 final_branch_condition = below_equal;
3651
3652 } else {
3653 final_branch_condition = not_equal;
3654 __ jmp(false_label);
3655 // A dead branch instruction will be generated after this point.
3656 }
3657
3658 return final_branch_condition;
3659}
3660
3661
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003662void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
3663 Register result = ToRegister(instr->result());
3664 NearLabel true_label;
3665 NearLabel false_label;
3666 NearLabel done;
3667
3668 EmitIsConstructCall(result);
3669 __ j(equal, &true_label);
3670
3671 __ mov(result, Factory::false_value());
3672 __ jmp(&done);
3673
3674 __ bind(&true_label);
3675 __ mov(result, Factory::true_value());
3676
3677 __ bind(&done);
3678}
3679
3680
3681void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
3682 Register temp = ToRegister(instr->TempAt(0));
3683 int true_block = chunk_->LookupDestination(instr->true_block_id());
3684 int false_block = chunk_->LookupDestination(instr->false_block_id());
3685
3686 EmitIsConstructCall(temp);
3687 EmitBranch(true_block, false_block, equal);
3688}
3689
3690
3691void LCodeGen::EmitIsConstructCall(Register temp) {
3692 // Get the frame pointer for the calling frame.
3693 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3694
3695 // Skip the arguments adaptor frame if it exists.
3696 NearLabel check_frame_marker;
3697 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
3698 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3699 __ j(not_equal, &check_frame_marker);
3700 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
3701
3702 // Check the marker in the calling frame.
3703 __ bind(&check_frame_marker);
3704 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
3705 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
3706}
3707
3708
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003709void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
3710 // No code for lazy bailout instruction. Used to capture environment after a
3711 // call for populating the safepoint data with deoptimization data.
3712}
3713
3714
3715void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
3716 DeoptimizeIf(no_condition, instr->environment());
3717}
3718
3719
3720void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
3721 LOperand* obj = instr->object();
3722 LOperand* key = instr->key();
3723 __ push(ToOperand(obj));
3724 if (key->IsConstantOperand()) {
3725 __ push(ToImmediate(key));
3726 } else {
3727 __ push(ToOperand(key));
3728 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003729 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
3730 LPointerMap* pointers = instr->pointer_map();
3731 LEnvironment* env = instr->deoptimization_environment();
3732 RecordPosition(pointers->position());
3733 RegisterEnvironmentForDeoptimization(env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003734 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003735 pointers,
3736 env->deoptimization_index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003737 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003738 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
3739}
3740
3741
3742void LCodeGen::DoStackCheck(LStackCheck* instr) {
3743 // Perform stack overflow check.
3744 NearLabel done;
3745 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
3746 __ cmp(esp, Operand::StaticVariable(stack_limit));
3747 __ j(above_equal, &done);
3748
3749 StackCheckStub stub;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003750 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003751 __ bind(&done);
3752}
3753
3754
3755void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
3756 // This is a pseudo-instruction that ensures that the environment here is
3757 // properly registered for deoptimization and records the assembler's PC
3758 // offset.
3759 LEnvironment* environment = instr->environment();
3760 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
3761 instr->SpilledDoubleRegisterArray());
3762
3763 // If the environment were already registered, we would have no way of
3764 // backpatching it with the spill slot operands.
3765 ASSERT(!environment->HasBeenRegistered());
3766 RegisterEnvironmentForDeoptimization(environment);
3767 ASSERT(osr_pc_offset_ == -1);
3768 osr_pc_offset_ = masm()->pc_offset();
3769}
3770
3771
3772#undef __
3773
3774} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003775
3776#endif // V8_TARGET_ARCH_IA32