blob: eb31d5aeeb339890dc7eb03f6f7b1f822d703720 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
33#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000034#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
40
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000041// When invoking builtins, we need to record the safepoint in the middle of
42// the invoke instruction sequence generated by the macro assembler.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000043class SafepointGenerator : public PostCallGenerator {
44 public:
45 SafepointGenerator(LCodeGen* codegen,
46 LPointerMap* pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000047 int deoptimization_index)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048 : codegen_(codegen),
49 pointers_(pointers),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000050 deoptimization_index_(deoptimization_index) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051 virtual ~SafepointGenerator() { }
52
53 virtual void Generate() {
54 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
55 }
56
57 private:
58 LCodeGen* codegen_;
59 LPointerMap* pointers_;
60 int deoptimization_index_;
61};
62
63
64#define __ masm()->
65
66bool LCodeGen::GenerateCode() {
67 HPhase phase("Code generation", chunk());
68 ASSERT(is_unused());
69 status_ = GENERATING;
70 CpuFeatures::Scope scope(SSE2);
71 return GeneratePrologue() &&
72 GenerateBody() &&
73 GenerateDeferredCode() &&
74 GenerateSafepointTable();
75}
76
77
78void LCodeGen::FinishCode(Handle<Code> code) {
79 ASSERT(is_done());
80 code->set_stack_slots(StackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000081 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000082 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000083 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000084}
85
86
87void LCodeGen::Abort(const char* format, ...) {
88 if (FLAG_trace_bailout) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000089 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
90 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000091 va_list arguments;
92 va_start(arguments, format);
93 OS::VPrint(format, arguments);
94 va_end(arguments);
95 PrintF("\n");
96 }
97 status_ = ABORTED;
98}
99
100
101void LCodeGen::Comment(const char* format, ...) {
102 if (!FLAG_code_comments) return;
103 char buffer[4 * KB];
104 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
105 va_list arguments;
106 va_start(arguments, format);
107 builder.AddFormattedList(format, arguments);
108 va_end(arguments);
109
110 // Copy the string before recording it in the assembler to avoid
111 // issues when the stack allocated buffer goes out of scope.
112 size_t length = builder.position();
113 Vector<char> copy = Vector<char>::New(length + 1);
114 memcpy(copy.start(), builder.Finalize(), copy.length());
115 masm()->RecordComment(copy.start());
116}
117
118
119bool LCodeGen::GeneratePrologue() {
120 ASSERT(is_generating());
121
122#ifdef DEBUG
123 if (strlen(FLAG_stop_at) > 0 &&
124 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
125 __ int3();
126 }
127#endif
128
129 __ push(ebp); // Caller's frame pointer.
130 __ mov(ebp, esp);
131 __ push(esi); // Callee's context.
132 __ push(edi); // Callee's JS function.
133
134 // Reserve space for the stack slots needed by the code.
135 int slots = StackSlotCount();
136 if (slots > 0) {
137 if (FLAG_debug_code) {
138 __ mov(Operand(eax), Immediate(slots));
139 Label loop;
140 __ bind(&loop);
141 __ push(Immediate(kSlotsZapValue));
142 __ dec(eax);
143 __ j(not_zero, &loop);
144 } else {
145 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000146#ifdef _MSC_VER
147 // On windows, you may not access the stack more than one page below
148 // the most recently mapped page. To make the allocated area randomly
149 // accessible, we write to each page in turn (the value is irrelevant).
150 const int kPageSize = 4 * KB;
151 for (int offset = slots * kPointerSize - kPageSize;
152 offset > 0;
153 offset -= kPageSize) {
154 __ mov(Operand(esp, offset), eax);
155 }
156#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000157 }
158 }
159
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000160 // Possibly allocate a local context.
161 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
162 if (heap_slots > 0) {
163 Comment(";;; Allocate local context");
164 // Argument to NewContext is the function, which is still in edi.
165 __ push(edi);
166 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
167 FastNewContextStub stub(heap_slots);
168 __ CallStub(&stub);
169 } else {
170 __ CallRuntime(Runtime::kNewContext, 1);
171 }
172 RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
173 // Context is returned in both eax and esi. It replaces the context
174 // passed to us. It's saved in the stack and kept live in esi.
175 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
176
177 // Copy parameters into context if necessary.
178 int num_parameters = scope()->num_parameters();
179 for (int i = 0; i < num_parameters; i++) {
180 Slot* slot = scope()->parameter(i)->AsSlot();
181 if (slot != NULL && slot->type() == Slot::CONTEXT) {
182 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
183 (num_parameters - 1 - i) * kPointerSize;
184 // Load parameter from stack.
185 __ mov(eax, Operand(ebp, parameter_offset));
186 // Store it in the context.
187 int context_offset = Context::SlotOffset(slot->index());
188 __ mov(Operand(esi, context_offset), eax);
189 // Update the write barrier. This clobbers all involved
190 // registers, so we have to use a third register to avoid
191 // clobbering esi.
192 __ mov(ecx, esi);
193 __ RecordWrite(ecx, context_offset, eax, ebx);
194 }
195 }
196 Comment(";;; End allocate local context");
197 }
198
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000199 // Trace the call.
200 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000201 // We have not executed any compiled code yet, so esi still holds the
202 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000203 __ CallRuntime(Runtime::kTraceEnter, 0);
204 }
205 return !is_aborted();
206}
207
208
209bool LCodeGen::GenerateBody() {
210 ASSERT(is_generating());
211 bool emit_instructions = true;
212 for (current_instruction_ = 0;
213 !is_aborted() && current_instruction_ < instructions_->length();
214 current_instruction_++) {
215 LInstruction* instr = instructions_->at(current_instruction_);
216 if (instr->IsLabel()) {
217 LLabel* label = LLabel::cast(instr);
218 emit_instructions = !label->HasReplacement();
219 }
220
221 if (emit_instructions) {
222 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
223 instr->CompileToNative(this);
224 }
225 }
226 return !is_aborted();
227}
228
229
230LInstruction* LCodeGen::GetNextInstruction() {
231 if (current_instruction_ < instructions_->length() - 1) {
232 return instructions_->at(current_instruction_ + 1);
233 } else {
234 return NULL;
235 }
236}
237
238
239bool LCodeGen::GenerateDeferredCode() {
240 ASSERT(is_generating());
241 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
242 LDeferredCode* code = deferred_[i];
243 __ bind(code->entry());
244 code->Generate();
245 __ jmp(code->exit());
246 }
247
248 // Deferred code is the last part of the instruction sequence. Mark
249 // the generated code as done unless we bailed out.
250 if (!is_aborted()) status_ = DONE;
251 return !is_aborted();
252}
253
254
255bool LCodeGen::GenerateSafepointTable() {
256 ASSERT(is_done());
257 safepoints_.Emit(masm(), StackSlotCount());
258 return !is_aborted();
259}
260
261
262Register LCodeGen::ToRegister(int index) const {
263 return Register::FromAllocationIndex(index);
264}
265
266
267XMMRegister LCodeGen::ToDoubleRegister(int index) const {
268 return XMMRegister::FromAllocationIndex(index);
269}
270
271
272Register LCodeGen::ToRegister(LOperand* op) const {
273 ASSERT(op->IsRegister());
274 return ToRegister(op->index());
275}
276
277
278XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
279 ASSERT(op->IsDoubleRegister());
280 return ToDoubleRegister(op->index());
281}
282
283
284int LCodeGen::ToInteger32(LConstantOperand* op) const {
285 Handle<Object> value = chunk_->LookupLiteral(op);
286 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
287 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
288 value->Number());
289 return static_cast<int32_t>(value->Number());
290}
291
292
293Immediate LCodeGen::ToImmediate(LOperand* op) {
294 LConstantOperand* const_op = LConstantOperand::cast(op);
295 Handle<Object> literal = chunk_->LookupLiteral(const_op);
296 Representation r = chunk_->LookupLiteralRepresentation(const_op);
297 if (r.IsInteger32()) {
298 ASSERT(literal->IsNumber());
299 return Immediate(static_cast<int32_t>(literal->Number()));
300 } else if (r.IsDouble()) {
301 Abort("unsupported double immediate");
302 }
303 ASSERT(r.IsTagged());
304 return Immediate(literal);
305}
306
307
308Operand LCodeGen::ToOperand(LOperand* op) const {
309 if (op->IsRegister()) return Operand(ToRegister(op));
310 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
311 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
312 int index = op->index();
313 if (index >= 0) {
314 // Local or spill slot. Skip the frame pointer, function, and
315 // context in the fixed part of the frame.
316 return Operand(ebp, -(index + 3) * kPointerSize);
317 } else {
318 // Incoming parameter. Skip the return address.
319 return Operand(ebp, -(index - 1) * kPointerSize);
320 }
321}
322
323
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000324Operand LCodeGen::HighOperand(LOperand* op) {
325 ASSERT(op->IsDoubleStackSlot());
326 int index = op->index();
327 int offset = (index >= 0) ? index + 3 : index - 1;
328 return Operand(ebp, -offset * kPointerSize);
329}
330
331
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000332void LCodeGen::WriteTranslation(LEnvironment* environment,
333 Translation* translation) {
334 if (environment == NULL) return;
335
336 // The translation includes one command per value in the environment.
337 int translation_size = environment->values()->length();
338 // The output frame height does not include the parameters.
339 int height = translation_size - environment->parameter_count();
340
341 WriteTranslation(environment->outer(), translation);
342 int closure_id = DefineDeoptimizationLiteral(environment->closure());
343 translation->BeginFrame(environment->ast_id(), closure_id, height);
344 for (int i = 0; i < translation_size; ++i) {
345 LOperand* value = environment->values()->at(i);
346 // spilled_registers_ and spilled_double_registers_ are either
347 // both NULL or both set.
348 if (environment->spilled_registers() != NULL && value != NULL) {
349 if (value->IsRegister() &&
350 environment->spilled_registers()[value->index()] != NULL) {
351 translation->MarkDuplicate();
352 AddToTranslation(translation,
353 environment->spilled_registers()[value->index()],
354 environment->HasTaggedValueAt(i));
355 } else if (
356 value->IsDoubleRegister() &&
357 environment->spilled_double_registers()[value->index()] != NULL) {
358 translation->MarkDuplicate();
359 AddToTranslation(
360 translation,
361 environment->spilled_double_registers()[value->index()],
362 false);
363 }
364 }
365
366 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
367 }
368}
369
370
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000371void LCodeGen::AddToTranslation(Translation* translation,
372 LOperand* op,
373 bool is_tagged) {
374 if (op == NULL) {
375 // TODO(twuerthinger): Introduce marker operands to indicate that this value
376 // is not present and must be reconstructed from the deoptimizer. Currently
377 // this is only used for the arguments object.
378 translation->StoreArgumentsObject();
379 } else if (op->IsStackSlot()) {
380 if (is_tagged) {
381 translation->StoreStackSlot(op->index());
382 } else {
383 translation->StoreInt32StackSlot(op->index());
384 }
385 } else if (op->IsDoubleStackSlot()) {
386 translation->StoreDoubleStackSlot(op->index());
387 } else if (op->IsArgument()) {
388 ASSERT(is_tagged);
389 int src_index = StackSlotCount() + op->index();
390 translation->StoreStackSlot(src_index);
391 } else if (op->IsRegister()) {
392 Register reg = ToRegister(op);
393 if (is_tagged) {
394 translation->StoreRegister(reg);
395 } else {
396 translation->StoreInt32Register(reg);
397 }
398 } else if (op->IsDoubleRegister()) {
399 XMMRegister reg = ToDoubleRegister(op);
400 translation->StoreDoubleRegister(reg);
401 } else if (op->IsConstantOperand()) {
402 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
403 int src_index = DefineDeoptimizationLiteral(literal);
404 translation->StoreLiteral(src_index);
405 } else {
406 UNREACHABLE();
407 }
408}
409
410
411void LCodeGen::CallCode(Handle<Code> code,
412 RelocInfo::Mode mode,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000413 LInstruction* instr,
414 bool adjusted) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000415 ASSERT(instr != NULL);
416 LPointerMap* pointers = instr->pointer_map();
417 RecordPosition(pointers->position());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000418
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000419 if (!adjusted) {
420 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
421 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000422 __ call(code, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000423
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000424 RegisterLazyDeoptimization(instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000425
426 // Signal that we don't inline smi code before these stubs in the
427 // optimizing code generator.
428 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
429 code->kind() == Code::COMPARE_IC) {
430 __ nop();
431 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000432}
433
434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000436 int argc,
437 LInstruction* instr,
438 bool adjusted) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000439 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000440 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000441 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000442 RecordPosition(pointers->position());
443
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000444 if (!adjusted) {
445 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
446 }
447 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000448
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000449 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450}
451
452
453void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
454 // Create the environment to bailout to. If the call has side effects
455 // execution has to continue after the call otherwise execution can continue
456 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000457 LEnvironment* deoptimization_environment;
458 if (instr->HasDeoptimizationEnvironment()) {
459 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000460 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000461 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000462 }
463
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000464 RegisterEnvironmentForDeoptimization(deoptimization_environment);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000465 RecordSafepoint(instr->pointer_map(),
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000466 deoptimization_environment->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467}
468
469
470void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
471 if (!environment->HasBeenRegistered()) {
472 // Physical stack frame layout:
473 // -x ............. -4 0 ..................................... y
474 // [incoming arguments] [spill slots] [pushed outgoing arguments]
475
476 // Layout of the environment:
477 // 0 ..................................................... size-1
478 // [parameters] [locals] [expression stack including arguments]
479
480 // Layout of the translation:
481 // 0 ........................................................ size - 1 + 4
482 // [expression stack including arguments] [locals] [4 words] [parameters]
483 // |>------------ translation_size ------------<|
484
485 int frame_count = 0;
486 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
487 ++frame_count;
488 }
489 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000490 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491 int deoptimization_index = deoptimizations_.length();
492 environment->Register(deoptimization_index, translation.index());
493 deoptimizations_.Add(environment);
494 }
495}
496
497
498void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
499 RegisterEnvironmentForDeoptimization(environment);
500 ASSERT(environment->HasBeenRegistered());
501 int id = environment->deoptimization_index();
502 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
503 ASSERT(entry != NULL);
504 if (entry == NULL) {
505 Abort("bailout was not prepared");
506 return;
507 }
508
509 if (FLAG_deopt_every_n_times != 0) {
510 Handle<SharedFunctionInfo> shared(info_->shared_info());
511 Label no_deopt;
512 __ pushfd();
513 __ push(eax);
514 __ push(ebx);
515 __ mov(ebx, shared);
516 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
517 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
518 __ j(not_zero, &no_deopt);
519 if (FLAG_trap_on_deopt) __ int3();
520 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
521 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
522 __ pop(ebx);
523 __ pop(eax);
524 __ popfd();
525 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
526
527 __ bind(&no_deopt);
528 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
529 __ pop(ebx);
530 __ pop(eax);
531 __ popfd();
532 }
533
534 if (cc == no_condition) {
535 if (FLAG_trap_on_deopt) __ int3();
536 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
537 } else {
538 if (FLAG_trap_on_deopt) {
539 NearLabel done;
540 __ j(NegateCondition(cc), &done);
541 __ int3();
542 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
543 __ bind(&done);
544 } else {
545 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY, not_taken);
546 }
547 }
548}
549
550
551void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
552 int length = deoptimizations_.length();
553 if (length == 0) return;
554 ASSERT(FLAG_deopt);
555 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000557
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000558 Handle<ByteArray> translations = translations_.CreateByteArray();
559 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000560 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
561
562 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000564 for (int i = 0; i < deoptimization_literals_.length(); i++) {
565 literals->set(i, *deoptimization_literals_[i]);
566 }
567 data->SetLiteralArray(*literals);
568
569 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
570 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
571
572 // Populate the deoptimization entries.
573 for (int i = 0; i < length; i++) {
574 LEnvironment* env = deoptimizations_[i];
575 data->SetAstId(i, Smi::FromInt(env->ast_id()));
576 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
577 data->SetArgumentsStackHeight(i,
578 Smi::FromInt(env->arguments_stack_height()));
579 }
580 code->set_deoptimization_data(*data);
581}
582
583
584int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
585 int result = deoptimization_literals_.length();
586 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
587 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
588 }
589 deoptimization_literals_.Add(literal);
590 return result;
591}
592
593
594void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
595 ASSERT(deoptimization_literals_.length() == 0);
596
597 const ZoneList<Handle<JSFunction> >* inlined_closures =
598 chunk()->inlined_closures();
599
600 for (int i = 0, length = inlined_closures->length();
601 i < length;
602 i++) {
603 DefineDeoptimizationLiteral(inlined_closures->at(i));
604 }
605
606 inlined_function_count_ = deoptimization_literals_.length();
607}
608
609
ager@chromium.org378b34e2011-01-28 08:04:38 +0000610void LCodeGen::RecordSafepoint(
611 LPointerMap* pointers,
612 Safepoint::Kind kind,
613 int arguments,
614 int deoptimization_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615 const ZoneList<LOperand*>* operands = pointers->operands();
616 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000617 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000618 for (int i = 0; i < operands->length(); i++) {
619 LOperand* pointer = operands->at(i);
620 if (pointer->IsStackSlot()) {
621 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000622 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
623 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000624 }
625 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000626}
627
628
629void LCodeGen::RecordSafepoint(LPointerMap* pointers,
630 int deoptimization_index) {
631 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632}
633
634
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000635void LCodeGen::RecordSafepoint(int deoptimization_index) {
636 LPointerMap empty_pointers(RelocInfo::kNoPosition);
637 RecordSafepoint(&empty_pointers, deoptimization_index);
638}
639
640
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000641void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
642 int arguments,
643 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000644 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
645 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646}
647
648
649void LCodeGen::RecordPosition(int position) {
650 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
651 masm()->positions_recorder()->RecordPosition(position);
652}
653
654
655void LCodeGen::DoLabel(LLabel* label) {
656 if (label->is_loop_header()) {
657 Comment(";;; B%d - LOOP entry", label->block_id());
658 } else {
659 Comment(";;; B%d", label->block_id());
660 }
661 __ bind(label->label());
662 current_block_ = label->block_id();
663 LCodeGen::DoGap(label);
664}
665
666
667void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000668 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000669}
670
671
672void LCodeGen::DoGap(LGap* gap) {
673 for (int i = LGap::FIRST_INNER_POSITION;
674 i <= LGap::LAST_INNER_POSITION;
675 i++) {
676 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
677 LParallelMove* move = gap->GetParallelMove(inner_pos);
678 if (move != NULL) DoParallelMove(move);
679 }
680
681 LInstruction* next = GetNextInstruction();
682 if (next != NULL && next->IsLazyBailout()) {
683 int pc = masm()->pc_offset();
684 safepoints_.SetPcAfterGap(pc);
685 }
686}
687
688
689void LCodeGen::DoParameter(LParameter* instr) {
690 // Nothing to do.
691}
692
693
694void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000695 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000696 ASSERT(ToRegister(instr->result()).is(eax));
697 switch (instr->hydrogen()->major_key()) {
698 case CodeStub::RegExpConstructResult: {
699 RegExpConstructResultStub stub;
700 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
701 break;
702 }
703 case CodeStub::RegExpExec: {
704 RegExpExecStub stub;
705 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
706 break;
707 }
708 case CodeStub::SubString: {
709 SubStringStub stub;
710 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
711 break;
712 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000713 case CodeStub::NumberToString: {
714 NumberToStringStub stub;
715 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
716 break;
717 }
718 case CodeStub::StringAdd: {
719 StringAddStub stub(NO_STRING_ADD_FLAGS);
720 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
721 break;
722 }
723 case CodeStub::StringCompare: {
724 StringCompareStub stub;
725 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
726 break;
727 }
728 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000729 TranscendentalCacheStub stub(instr->transcendental_type(),
730 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000731 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
732 break;
733 }
734 default:
735 UNREACHABLE();
736 }
737}
738
739
740void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
741 // Nothing to do.
742}
743
744
745void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000746 if (instr->hydrogen()->HasPowerOf2Divisor()) {
747 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000748
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000749 int32_t divisor =
750 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000751
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000752 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000753
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000754 NearLabel positive_dividend, done;
755 __ test(dividend, Operand(dividend));
756 __ j(not_sign, &positive_dividend);
757 __ neg(dividend);
758 __ and_(dividend, divisor - 1);
759 __ neg(dividend);
760 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
761 __ j(not_zero, &done);
762 DeoptimizeIf(no_condition, instr->environment());
763 }
764 __ bind(&positive_dividend);
765 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000766 __ bind(&done);
767 } else {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000768 LOperand* right = instr->InputAt(1);
769 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
770 ASSERT(ToRegister(instr->result()).is(edx));
771
772 Register right_reg = ToRegister(right);
773 ASSERT(!right_reg.is(eax));
774 ASSERT(!right_reg.is(edx));
775
776 // Check for x % 0.
777 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
778 __ test(right_reg, ToOperand(right));
779 DeoptimizeIf(zero, instr->environment());
780 }
781
782 // Sign extend to edx.
783 __ cdq();
784
785 // Check for (0 % -x) that will produce negative zero.
786 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
787 NearLabel positive_left;
788 NearLabel done;
789 __ test(eax, Operand(eax));
790 __ j(not_sign, &positive_left);
791 __ idiv(right_reg);
792
793 // Test the remainder for 0, because then the result would be -0.
794 __ test(edx, Operand(edx));
795 __ j(not_zero, &done);
796
797 DeoptimizeIf(no_condition, instr->environment());
798 __ bind(&positive_left);
799 __ idiv(right_reg);
800 __ bind(&done);
801 } else {
802 __ idiv(right_reg);
803 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000804 }
805}
806
807
808void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000809 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000810 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000811 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
812 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
813 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000814
815 Register left_reg = eax;
816
817 // Check for x / 0.
818 Register right_reg = ToRegister(right);
819 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
820 __ test(right_reg, ToOperand(right));
821 DeoptimizeIf(zero, instr->environment());
822 }
823
824 // Check for (0 / -x) that will produce negative zero.
825 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
826 NearLabel left_not_zero;
827 __ test(left_reg, Operand(left_reg));
828 __ j(not_zero, &left_not_zero);
829 __ test(right_reg, ToOperand(right));
830 DeoptimizeIf(sign, instr->environment());
831 __ bind(&left_not_zero);
832 }
833
834 // Check for (-kMinInt / -1).
835 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
836 NearLabel left_not_min_int;
837 __ cmp(left_reg, kMinInt);
838 __ j(not_zero, &left_not_min_int);
839 __ cmp(right_reg, -1);
840 DeoptimizeIf(zero, instr->environment());
841 __ bind(&left_not_min_int);
842 }
843
844 // Sign extend to edx.
845 __ cdq();
846 __ idiv(right_reg);
847
848 // Deoptimize if remainder is not 0.
849 __ test(edx, Operand(edx));
850 DeoptimizeIf(not_zero, instr->environment());
851}
852
853
854void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000855 Register left = ToRegister(instr->InputAt(0));
856 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000857
858 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000859 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000860 }
861
862 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000863 // Try strength reductions on the multiplication.
864 // All replacement instructions are at most as long as the imul
865 // and have better latency.
866 int constant = ToInteger32(LConstantOperand::cast(right));
867 if (constant == -1) {
868 __ neg(left);
869 } else if (constant == 0) {
870 __ xor_(left, Operand(left));
871 } else if (constant == 2) {
872 __ add(left, Operand(left));
873 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
874 // If we know that the multiplication can't overflow, it's safe to
875 // use instructions that don't set the overflow flag for the
876 // multiplication.
877 switch (constant) {
878 case 1:
879 // Do nothing.
880 break;
881 case 3:
882 __ lea(left, Operand(left, left, times_2, 0));
883 break;
884 case 4:
885 __ shl(left, 2);
886 break;
887 case 5:
888 __ lea(left, Operand(left, left, times_4, 0));
889 break;
890 case 8:
891 __ shl(left, 3);
892 break;
893 case 9:
894 __ lea(left, Operand(left, left, times_8, 0));
895 break;
896 case 16:
897 __ shl(left, 4);
898 break;
899 default:
900 __ imul(left, left, constant);
901 break;
902 }
903 } else {
904 __ imul(left, left, constant);
905 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000906 } else {
907 __ imul(left, ToOperand(right));
908 }
909
910 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
911 DeoptimizeIf(overflow, instr->environment());
912 }
913
914 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
915 // Bail out if the result is supposed to be negative zero.
916 NearLabel done;
917 __ test(left, Operand(left));
918 __ j(not_zero, &done);
919 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000920 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000921 DeoptimizeIf(no_condition, instr->environment());
922 }
923 } else {
924 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000925 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000926 DeoptimizeIf(sign, instr->environment());
927 }
928 __ bind(&done);
929 }
930}
931
932
933void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000934 LOperand* left = instr->InputAt(0);
935 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000936 ASSERT(left->Equals(instr->result()));
937 ASSERT(left->IsRegister());
938
939 if (right->IsConstantOperand()) {
940 int right_operand = ToInteger32(LConstantOperand::cast(right));
941 switch (instr->op()) {
942 case Token::BIT_AND:
943 __ and_(ToRegister(left), right_operand);
944 break;
945 case Token::BIT_OR:
946 __ or_(ToRegister(left), right_operand);
947 break;
948 case Token::BIT_XOR:
949 __ xor_(ToRegister(left), right_operand);
950 break;
951 default:
952 UNREACHABLE();
953 break;
954 }
955 } else {
956 switch (instr->op()) {
957 case Token::BIT_AND:
958 __ and_(ToRegister(left), ToOperand(right));
959 break;
960 case Token::BIT_OR:
961 __ or_(ToRegister(left), ToOperand(right));
962 break;
963 case Token::BIT_XOR:
964 __ xor_(ToRegister(left), ToOperand(right));
965 break;
966 default:
967 UNREACHABLE();
968 break;
969 }
970 }
971}
972
973
974void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000975 LOperand* left = instr->InputAt(0);
976 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000977 ASSERT(left->Equals(instr->result()));
978 ASSERT(left->IsRegister());
979 if (right->IsRegister()) {
980 ASSERT(ToRegister(right).is(ecx));
981
982 switch (instr->op()) {
983 case Token::SAR:
984 __ sar_cl(ToRegister(left));
985 break;
986 case Token::SHR:
987 __ shr_cl(ToRegister(left));
988 if (instr->can_deopt()) {
989 __ test(ToRegister(left), Immediate(0x80000000));
990 DeoptimizeIf(not_zero, instr->environment());
991 }
992 break;
993 case Token::SHL:
994 __ shl_cl(ToRegister(left));
995 break;
996 default:
997 UNREACHABLE();
998 break;
999 }
1000 } else {
1001 int value = ToInteger32(LConstantOperand::cast(right));
1002 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1003 switch (instr->op()) {
1004 case Token::SAR:
1005 if (shift_count != 0) {
1006 __ sar(ToRegister(left), shift_count);
1007 }
1008 break;
1009 case Token::SHR:
1010 if (shift_count == 0 && instr->can_deopt()) {
1011 __ test(ToRegister(left), Immediate(0x80000000));
1012 DeoptimizeIf(not_zero, instr->environment());
1013 } else {
1014 __ shr(ToRegister(left), shift_count);
1015 }
1016 break;
1017 case Token::SHL:
1018 if (shift_count != 0) {
1019 __ shl(ToRegister(left), shift_count);
1020 }
1021 break;
1022 default:
1023 UNREACHABLE();
1024 break;
1025 }
1026 }
1027}
1028
1029
1030void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001031 LOperand* left = instr->InputAt(0);
1032 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 ASSERT(left->Equals(instr->result()));
1034
1035 if (right->IsConstantOperand()) {
1036 __ sub(ToOperand(left), ToImmediate(right));
1037 } else {
1038 __ sub(ToRegister(left), ToOperand(right));
1039 }
1040 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1041 DeoptimizeIf(overflow, instr->environment());
1042 }
1043}
1044
1045
1046void LCodeGen::DoConstantI(LConstantI* instr) {
1047 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001048 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001049}
1050
1051
1052void LCodeGen::DoConstantD(LConstantD* instr) {
1053 ASSERT(instr->result()->IsDoubleRegister());
1054 XMMRegister res = ToDoubleRegister(instr->result());
1055 double v = instr->value();
1056 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1057 // do so if the constant is -0.0.
1058 if (BitCast<uint64_t, double>(v) == 0) {
1059 __ xorpd(res, res);
1060 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001061 Register temp = ToRegister(instr->TempAt(0));
1062 uint64_t int_val = BitCast<uint64_t, double>(v);
1063 int32_t lower = static_cast<int32_t>(int_val);
1064 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001066 CpuFeatures::Scope scope(SSE4_1);
1067 if (lower != 0) {
1068 __ Set(temp, Immediate(lower));
1069 __ movd(res, Operand(temp));
1070 __ Set(temp, Immediate(upper));
1071 __ pinsrd(res, Operand(temp), 1);
1072 } else {
1073 __ xorpd(res, res);
1074 __ Set(temp, Immediate(upper));
1075 __ pinsrd(res, Operand(temp), 1);
1076 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001077 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001078 __ Set(temp, Immediate(upper));
1079 __ movd(res, Operand(temp));
1080 __ psllq(res, 32);
1081 if (lower != 0) {
1082 __ Set(temp, Immediate(lower));
1083 __ movd(xmm0, Operand(temp));
1084 __ por(res, xmm0);
1085 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001086 }
1087 }
1088}
1089
1090
1091void LCodeGen::DoConstantT(LConstantT* instr) {
1092 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001093 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001094}
1095
1096
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001097void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001098 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001099 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001100 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1101}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001102
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001103
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001104void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
1105 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001106 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001107 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001108}
1109
1110
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001111void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001112 Register result = ToRegister(instr->result());
1113 Register array = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001114 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001115}
1116
1117
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001118void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001119 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001120 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001121 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001122 ASSERT(input.is(result));
1123 NearLabel done;
1124 // If the object is a smi return the object.
1125 __ test(input, Immediate(kSmiTagMask));
1126 __ j(zero, &done);
1127
1128 // If the object is not a value type, return the object.
1129 __ CmpObjectType(input, JS_VALUE_TYPE, map);
1130 __ j(not_equal, &done);
1131 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1132
1133 __ bind(&done);
1134}
1135
1136
1137void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001138 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001139 ASSERT(input->Equals(instr->result()));
1140 __ not_(ToRegister(input));
1141}
1142
1143
1144void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001145 __ push(ToOperand(instr->InputAt(0)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001146 CallRuntime(Runtime::kThrow, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001147
1148 if (FLAG_debug_code) {
1149 Comment("Unreachable code.");
1150 __ int3();
1151 }
1152}
1153
1154
1155void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001156 LOperand* left = instr->InputAt(0);
1157 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001158 ASSERT(left->Equals(instr->result()));
1159
1160 if (right->IsConstantOperand()) {
1161 __ add(ToOperand(left), ToImmediate(right));
1162 } else {
1163 __ add(ToRegister(left), ToOperand(right));
1164 }
1165
1166 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1167 DeoptimizeIf(overflow, instr->environment());
1168 }
1169}
1170
1171
1172void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001173 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1174 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1175 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001176 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001177 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001178 switch (instr->op()) {
1179 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001180 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001181 break;
1182 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001183 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184 break;
1185 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001186 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001187 break;
1188 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001189 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001190 break;
1191 case Token::MOD: {
1192 // Pass two doubles as arguments on the stack.
1193 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001194 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1195 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001196 __ CallCFunction(
1197 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1198 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199
1200 // Return value is in st(0) on ia32.
1201 // Store it into the (fixed) result register.
1202 __ sub(Operand(esp), Immediate(kDoubleSize));
1203 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001204 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001205 __ add(Operand(esp), Immediate(kDoubleSize));
1206 break;
1207 }
1208 default:
1209 UNREACHABLE();
1210 break;
1211 }
1212}
1213
1214
1215void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001216 ASSERT(ToRegister(instr->InputAt(0)).is(edx));
1217 ASSERT(ToRegister(instr->InputAt(1)).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001218 ASSERT(ToRegister(instr->result()).is(eax));
1219
1220 TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001221 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001222}
1223
1224
1225int LCodeGen::GetNextEmittedBlock(int block) {
1226 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1227 LLabel* label = chunk_->GetLabel(i);
1228 if (!label->HasReplacement()) return i;
1229 }
1230 return -1;
1231}
1232
1233
1234void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1235 int next_block = GetNextEmittedBlock(current_block_);
1236 right_block = chunk_->LookupDestination(right_block);
1237 left_block = chunk_->LookupDestination(left_block);
1238
1239 if (right_block == left_block) {
1240 EmitGoto(left_block);
1241 } else if (left_block == next_block) {
1242 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1243 } else if (right_block == next_block) {
1244 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1245 } else {
1246 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1247 __ jmp(chunk_->GetAssemblyLabel(right_block));
1248 }
1249}
1250
1251
1252void LCodeGen::DoBranch(LBranch* instr) {
1253 int true_block = chunk_->LookupDestination(instr->true_block_id());
1254 int false_block = chunk_->LookupDestination(instr->false_block_id());
1255
1256 Representation r = instr->hydrogen()->representation();
1257 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001258 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001259 __ test(reg, Operand(reg));
1260 EmitBranch(true_block, false_block, not_zero);
1261 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001262 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001263 __ xorpd(xmm0, xmm0);
1264 __ ucomisd(reg, xmm0);
1265 EmitBranch(true_block, false_block, not_equal);
1266 } else {
1267 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001268 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001269 if (instr->hydrogen()->type().IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001270 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001271 EmitBranch(true_block, false_block, equal);
1272 } else {
1273 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1274 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1275
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001277 __ j(equal, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001279 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001280 __ cmp(reg, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001281 __ j(equal, false_label);
1282 __ test(reg, Operand(reg));
1283 __ j(equal, false_label);
1284 __ test(reg, Immediate(kSmiTagMask));
1285 __ j(zero, true_label);
1286
1287 // Test for double values. Zero is false.
1288 NearLabel call_stub;
1289 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001291 __ j(not_equal, &call_stub);
1292 __ fldz();
1293 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1294 __ FCmp();
1295 __ j(zero, false_label);
1296 __ jmp(true_label);
1297
1298 // The conversion stub doesn't cause garbage collections so it's
1299 // safe to not record a safepoint after the call.
1300 __ bind(&call_stub);
1301 ToBooleanStub stub;
1302 __ pushad();
1303 __ push(reg);
1304 __ CallStub(&stub);
1305 __ test(eax, Operand(eax));
1306 __ popad();
1307 EmitBranch(true_block, false_block, not_zero);
1308 }
1309 }
1310}
1311
1312
1313void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
1314 block = chunk_->LookupDestination(block);
1315 int next_block = GetNextEmittedBlock(current_block_);
1316 if (block != next_block) {
1317 // Perform stack overflow check if this goto needs it before jumping.
1318 if (deferred_stack_check != NULL) {
1319 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001321 __ cmp(esp, Operand::StaticVariable(stack_limit));
1322 __ j(above_equal, chunk_->GetAssemblyLabel(block));
1323 __ jmp(deferred_stack_check->entry());
1324 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1325 } else {
1326 __ jmp(chunk_->GetAssemblyLabel(block));
1327 }
1328 }
1329}
1330
1331
1332void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
1333 __ pushad();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001334 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001335 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
1336 RecordSafepointWithRegisters(
1337 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1338 __ popad();
1339}
1340
1341void LCodeGen::DoGoto(LGoto* instr) {
1342 class DeferredStackCheck: public LDeferredCode {
1343 public:
1344 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1345 : LDeferredCode(codegen), instr_(instr) { }
1346 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1347 private:
1348 LGoto* instr_;
1349 };
1350
1351 DeferredStackCheck* deferred = NULL;
1352 if (instr->include_stack_check()) {
1353 deferred = new DeferredStackCheck(this, instr);
1354 }
1355 EmitGoto(instr->block_id(), deferred);
1356}
1357
1358
1359Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1360 Condition cond = no_condition;
1361 switch (op) {
1362 case Token::EQ:
1363 case Token::EQ_STRICT:
1364 cond = equal;
1365 break;
1366 case Token::LT:
1367 cond = is_unsigned ? below : less;
1368 break;
1369 case Token::GT:
1370 cond = is_unsigned ? above : greater;
1371 break;
1372 case Token::LTE:
1373 cond = is_unsigned ? below_equal : less_equal;
1374 break;
1375 case Token::GTE:
1376 cond = is_unsigned ? above_equal : greater_equal;
1377 break;
1378 case Token::IN:
1379 case Token::INSTANCEOF:
1380 default:
1381 UNREACHABLE();
1382 }
1383 return cond;
1384}
1385
1386
1387void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
1388 if (right->IsConstantOperand()) {
1389 __ cmp(ToOperand(left), ToImmediate(right));
1390 } else {
1391 __ cmp(ToRegister(left), ToOperand(right));
1392 }
1393}
1394
1395
1396void LCodeGen::DoCmpID(LCmpID* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001397 LOperand* left = instr->InputAt(0);
1398 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001399 LOperand* result = instr->result();
1400
1401 NearLabel unordered;
1402 if (instr->is_double()) {
1403 // Don't base result on EFLAGS when a NaN is involved. Instead
1404 // jump to the unordered case, which produces a false value.
1405 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1406 __ j(parity_even, &unordered, not_taken);
1407 } else {
1408 EmitCmpI(left, right);
1409 }
1410
1411 NearLabel done;
1412 Condition cc = TokenToCondition(instr->op(), instr->is_double());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 __ mov(ToRegister(result), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001414 __ j(cc, &done);
1415
1416 __ bind(&unordered);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001417 __ mov(ToRegister(result), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001418 __ bind(&done);
1419}
1420
1421
1422void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001423 LOperand* left = instr->InputAt(0);
1424 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001425 int false_block = chunk_->LookupDestination(instr->false_block_id());
1426 int true_block = chunk_->LookupDestination(instr->true_block_id());
1427
1428 if (instr->is_double()) {
1429 // Don't base result on EFLAGS when a NaN is involved. Instead
1430 // jump to the false block.
1431 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1432 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1433 } else {
1434 EmitCmpI(left, right);
1435 }
1436
1437 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1438 EmitBranch(true_block, false_block, cc);
1439}
1440
1441
1442void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001443 Register left = ToRegister(instr->InputAt(0));
1444 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001445 Register result = ToRegister(instr->result());
1446
1447 __ cmp(left, Operand(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001449 NearLabel done;
1450 __ j(equal, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001452 __ bind(&done);
1453}
1454
1455
1456void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001457 Register left = ToRegister(instr->InputAt(0));
1458 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001459 int false_block = chunk_->LookupDestination(instr->false_block_id());
1460 int true_block = chunk_->LookupDestination(instr->true_block_id());
1461
1462 __ cmp(left, Operand(right));
1463 EmitBranch(true_block, false_block, equal);
1464}
1465
1466
1467void LCodeGen::DoIsNull(LIsNull* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001468 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001469 Register result = ToRegister(instr->result());
1470
1471 // TODO(fsc): If the expression is known to be a smi, then it's
1472 // definitely not null. Materialize false.
1473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001475 if (instr->is_strict()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001476 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001477 NearLabel done;
1478 __ j(equal, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001479 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001480 __ bind(&done);
1481 } else {
1482 NearLabel true_value, false_value, done;
1483 __ j(equal, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001485 __ j(equal, &true_value);
1486 __ test(reg, Immediate(kSmiTagMask));
1487 __ j(zero, &false_value);
1488 // Check for undetectable objects by looking in the bit field in
1489 // the map. The object has already been smi checked.
1490 Register scratch = result;
1491 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1492 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1493 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1494 __ j(not_zero, &true_value);
1495 __ bind(&false_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001497 __ jmp(&done);
1498 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001499 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001500 __ bind(&done);
1501 }
1502}
1503
1504
1505void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001506 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001507
1508 // TODO(fsc): If the expression is known to be a smi, then it's
1509 // definitely not null. Jump to the false block.
1510
1511 int true_block = chunk_->LookupDestination(instr->true_block_id());
1512 int false_block = chunk_->LookupDestination(instr->false_block_id());
1513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001515 if (instr->is_strict()) {
1516 EmitBranch(true_block, false_block, equal);
1517 } else {
1518 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1519 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1520 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 __ j(equal, true_label);
1523 __ test(reg, Immediate(kSmiTagMask));
1524 __ j(zero, false_label);
1525 // Check for undetectable objects by looking in the bit field in
1526 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001527 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001528 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1529 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1530 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1531 EmitBranch(true_block, false_block, not_zero);
1532 }
1533}
1534
1535
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001536Condition LCodeGen::EmitIsObject(Register input,
1537 Register temp1,
1538 Register temp2,
1539 Label* is_not_object,
1540 Label* is_object) {
1541 ASSERT(!input.is(temp1));
1542 ASSERT(!input.is(temp2));
1543 ASSERT(!temp1.is(temp2));
1544
1545 __ test(input, Immediate(kSmiTagMask));
1546 __ j(equal, is_not_object);
1547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001549 __ j(equal, is_object);
1550
1551 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1552 // Undetectable objects behave like undefined.
1553 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
1554 __ test(temp2, Immediate(1 << Map::kIsUndetectable));
1555 __ j(not_zero, is_not_object);
1556
1557 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
1558 __ cmp(temp2, FIRST_JS_OBJECT_TYPE);
1559 __ j(below, is_not_object);
1560 __ cmp(temp2, LAST_JS_OBJECT_TYPE);
1561 return below_equal;
1562}
1563
1564
1565void LCodeGen::DoIsObject(LIsObject* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001566 Register reg = ToRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001567 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001568 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001569 Label is_false, is_true, done;
1570
1571 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1572 __ j(true_cond, &is_true);
1573
1574 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001575 __ mov(result, factory()->false_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001576 __ jmp(&done);
1577
1578 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001579 __ mov(result, factory()->true_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001580
1581 __ bind(&done);
1582}
1583
1584
1585void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001586 Register reg = ToRegister(instr->InputAt(0));
1587 Register temp = ToRegister(instr->TempAt(0));
1588 Register temp2 = ToRegister(instr->TempAt(1));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001589
1590 int true_block = chunk_->LookupDestination(instr->true_block_id());
1591 int false_block = chunk_->LookupDestination(instr->false_block_id());
1592 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1593 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1594
1595 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
1596
1597 EmitBranch(true_block, false_block, true_cond);
1598}
1599
1600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001601void LCodeGen::DoIsSmi(LIsSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001602 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001603 Register result = ToRegister(instr->result());
1604
1605 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1606 __ test(input, Immediate(kSmiTagMask));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001608 NearLabel done;
1609 __ j(zero, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001611 __ bind(&done);
1612}
1613
1614
1615void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001616 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617
1618 int true_block = chunk_->LookupDestination(instr->true_block_id());
1619 int false_block = chunk_->LookupDestination(instr->false_block_id());
1620
1621 __ test(input, Immediate(kSmiTagMask));
1622 EmitBranch(true_block, false_block, zero);
1623}
1624
1625
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001626static InstanceType TestType(HHasInstanceType* instr) {
1627 InstanceType from = instr->from();
1628 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001629 if (from == FIRST_TYPE) return to;
1630 ASSERT(from == to || to == LAST_TYPE);
1631 return from;
1632}
1633
1634
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001635static Condition BranchCondition(HHasInstanceType* instr) {
1636 InstanceType from = instr->from();
1637 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001638 if (from == to) return equal;
1639 if (to == LAST_TYPE) return above_equal;
1640 if (from == FIRST_TYPE) return below_equal;
1641 UNREACHABLE();
1642 return equal;
1643}
1644
1645
1646void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001647 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001648 Register result = ToRegister(instr->result());
1649
1650 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1651 __ test(input, Immediate(kSmiTagMask));
1652 NearLabel done, is_false;
1653 __ j(zero, &is_false);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001654 __ CmpObjectType(input, TestType(instr->hydrogen()), result);
1655 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001656 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001657 __ jmp(&done);
1658 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001660 __ bind(&done);
1661}
1662
1663
1664void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001665 Register input = ToRegister(instr->InputAt(0));
1666 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001667
1668 int true_block = chunk_->LookupDestination(instr->true_block_id());
1669 int false_block = chunk_->LookupDestination(instr->false_block_id());
1670
1671 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1672
1673 __ test(input, Immediate(kSmiTagMask));
1674 __ j(zero, false_label);
1675
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001676 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1677 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678}
1679
1680
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001681void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1682 Register input = ToRegister(instr->InputAt(0));
1683 Register result = ToRegister(instr->result());
1684
1685 if (FLAG_debug_code) {
1686 __ AbortIfNotString(input);
1687 }
1688
1689 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
1690 __ IndexFromHash(result, result);
1691}
1692
1693
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001694void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001695 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001696 Register result = ToRegister(instr->result());
1697
1698 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001700 __ test(FieldOperand(input, String::kHashFieldOffset),
1701 Immediate(String::kContainsCachedArrayIndexMask));
1702 NearLabel done;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001703 __ j(zero, &done);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001705 __ bind(&done);
1706}
1707
1708
1709void LCodeGen::DoHasCachedArrayIndexAndBranch(
1710 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001711 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001712
1713 int true_block = chunk_->LookupDestination(instr->true_block_id());
1714 int false_block = chunk_->LookupDestination(instr->false_block_id());
1715
1716 __ test(FieldOperand(input, String::kHashFieldOffset),
1717 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001718 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001719}
1720
1721
1722// Branches to a label or falls through with the answer in the z flag. Trashes
1723// the temp registers, but not the input. Only input and temp2 may alias.
1724void LCodeGen::EmitClassOfTest(Label* is_true,
1725 Label* is_false,
1726 Handle<String>class_name,
1727 Register input,
1728 Register temp,
1729 Register temp2) {
1730 ASSERT(!input.is(temp));
1731 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
1732 __ test(input, Immediate(kSmiTagMask));
1733 __ j(zero, is_false);
1734 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
1735 __ j(below, is_false);
1736
1737 // Map is now in temp.
1738 // Functions have class 'Function'.
1739 __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
1740 if (class_name->IsEqualTo(CStrVector("Function"))) {
1741 __ j(equal, is_true);
1742 } else {
1743 __ j(equal, is_false);
1744 }
1745
1746 // Check if the constructor in the map is a function.
1747 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
1748
1749 // As long as JS_FUNCTION_TYPE is the last instance type and it is
1750 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1751 // LAST_JS_OBJECT_TYPE.
1752 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1753 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
1754
1755 // Objects with a non-function constructor have class 'Object'.
1756 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1757 if (class_name->IsEqualTo(CStrVector("Object"))) {
1758 __ j(not_equal, is_true);
1759 } else {
1760 __ j(not_equal, is_false);
1761 }
1762
1763 // temp now contains the constructor function. Grab the
1764 // instance class name from there.
1765 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1766 __ mov(temp, FieldOperand(temp,
1767 SharedFunctionInfo::kInstanceClassNameOffset));
1768 // The class name we are testing against is a symbol because it's a literal.
1769 // The name in the constructor is a symbol because of the way the context is
1770 // booted. This routine isn't expected to work for random API-created
1771 // classes and it doesn't have to because you can't access it with natives
1772 // syntax. Since both sides are symbols it is sufficient to use an identity
1773 // comparison.
1774 __ cmp(temp, class_name);
1775 // End with the answer in the z flag.
1776}
1777
1778
1779void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001780 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001781 Register result = ToRegister(instr->result());
1782 ASSERT(input.is(result));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001783 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001784 Handle<String> class_name = instr->hydrogen()->class_name();
1785 NearLabel done;
1786 Label is_true, is_false;
1787
1788 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
1789
1790 __ j(not_equal, &is_false);
1791
1792 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001794 __ jmp(&done);
1795
1796 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001798 __ bind(&done);
1799}
1800
1801
1802void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001803 Register input = ToRegister(instr->InputAt(0));
1804 Register temp = ToRegister(instr->TempAt(0));
1805 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001806 if (input.is(temp)) {
1807 // Swap.
1808 Register swapper = temp;
1809 temp = temp2;
1810 temp2 = swapper;
1811 }
1812 Handle<String> class_name = instr->hydrogen()->class_name();
1813
1814 int true_block = chunk_->LookupDestination(instr->true_block_id());
1815 int false_block = chunk_->LookupDestination(instr->false_block_id());
1816
1817 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1818 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1819
1820 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1821
1822 EmitBranch(true_block, false_block, equal);
1823}
1824
1825
1826void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001827 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001828 int true_block = instr->true_block_id();
1829 int false_block = instr->false_block_id();
1830
1831 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1832 EmitBranch(true_block, false_block, equal);
1833}
1834
1835
1836void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001838 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001839 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001840 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1841
1842 NearLabel true_value, done;
1843 __ test(eax, Operand(eax));
1844 __ j(zero, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 __ mov(ToRegister(instr->result()), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001846 __ jmp(&done);
1847 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001849 __ bind(&done);
1850}
1851
1852
1853void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001854 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001855 int true_block = chunk_->LookupDestination(instr->true_block_id());
1856 int false_block = chunk_->LookupDestination(instr->false_block_id());
1857
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001858 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001859 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1860 __ test(eax, Operand(eax));
1861 EmitBranch(true_block, false_block, zero);
1862}
1863
1864
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001865void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1866 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1867 public:
1868 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1869 LInstanceOfKnownGlobal* instr)
1870 : LDeferredCode(codegen), instr_(instr) { }
1871 virtual void Generate() {
1872 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
1873 }
1874
1875 Label* map_check() { return &map_check_; }
1876
1877 private:
1878 LInstanceOfKnownGlobal* instr_;
1879 Label map_check_;
1880 };
1881
1882 DeferredInstanceOfKnownGlobal* deferred;
1883 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1884
1885 Label done, false_result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001886 Register object = ToRegister(instr->InputAt(0));
1887 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001888
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001889 // A Smi is not an instance of anything.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001890 __ test(object, Immediate(kSmiTagMask));
1891 __ j(zero, &false_result, not_taken);
1892
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001893 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001894 // hole value will be patched to the last map/result pair generated by the
1895 // instanceof stub.
1896 NearLabel cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001897 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001898 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
1899 __ bind(deferred->map_check()); // Label for calculating code patching.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001901 __ j(not_equal, &cache_miss, not_taken);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001902 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001903 __ jmp(&done);
1904
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001905 // The inlined call site cache did not match. Check for null and string
1906 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001907 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001908 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001909 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001910 __ j(equal, &false_result);
1911
1912 // String values are not instances of anything.
1913 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
1914 __ j(is_string, &false_result);
1915
1916 // Go to the deferred code.
1917 __ jmp(deferred->entry());
1918
1919 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001920 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001921
1922 // Here result has either true or false. Deferred code also produces true or
1923 // false object.
1924 __ bind(deferred->exit());
1925 __ bind(&done);
1926}
1927
1928
1929void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
1930 Label* map_check) {
1931 __ PushSafepointRegisters();
1932
1933 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
1934 flags = static_cast<InstanceofStub::Flags>(
1935 flags | InstanceofStub::kArgsInRegisters);
1936 flags = static_cast<InstanceofStub::Flags>(
1937 flags | InstanceofStub::kCallSiteInlineCheck);
1938 flags = static_cast<InstanceofStub::Flags>(
1939 flags | InstanceofStub::kReturnTrueFalseObject);
1940 InstanceofStub stub(flags);
1941
1942 // Get the temp register reserved by the instruction. This needs to be edi as
1943 // its slot of the pushing of safepoint registers is used to communicate the
1944 // offset to the location of the map check.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001945 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001946 ASSERT(temp.is(edi));
1947 __ mov(InstanceofStub::right(), Immediate(instr->function()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001948 static const int kAdditionalDelta = 16;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001949 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001950 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001951 __ StoreToSafepointRegisterSlot(temp, temp);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001952 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001953 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001954 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001955 __ PopSafepointRegisters();
1956}
1957
1958
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959static Condition ComputeCompareCondition(Token::Value op) {
1960 switch (op) {
1961 case Token::EQ_STRICT:
1962 case Token::EQ:
1963 return equal;
1964 case Token::LT:
1965 return less;
1966 case Token::GT:
1967 return greater;
1968 case Token::LTE:
1969 return less_equal;
1970 case Token::GTE:
1971 return greater_equal;
1972 default:
1973 UNREACHABLE();
1974 return no_condition;
1975 }
1976}
1977
1978
1979void LCodeGen::DoCmpT(LCmpT* instr) {
1980 Token::Value op = instr->op();
1981
1982 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001983 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001984
1985 Condition condition = ComputeCompareCondition(op);
1986 if (op == Token::GT || op == Token::LTE) {
1987 condition = ReverseCondition(condition);
1988 }
1989 NearLabel true_value, done;
1990 __ test(eax, Operand(eax));
1991 __ j(condition, &true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001992 __ mov(ToRegister(instr->result()), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001993 __ jmp(&done);
1994 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001995 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 __ bind(&done);
1997}
1998
1999
2000void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
2001 Token::Value op = instr->op();
2002 int true_block = chunk_->LookupDestination(instr->true_block_id());
2003 int false_block = chunk_->LookupDestination(instr->false_block_id());
2004
2005 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002006 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002007
2008 // The compare stub expects compare condition and the input operands
2009 // reversed for GT and LTE.
2010 Condition condition = ComputeCompareCondition(op);
2011 if (op == Token::GT || op == Token::LTE) {
2012 condition = ReverseCondition(condition);
2013 }
2014 __ test(eax, Operand(eax));
2015 EmitBranch(true_block, false_block, condition);
2016}
2017
2018
2019void LCodeGen::DoReturn(LReturn* instr) {
2020 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002021 // Preserve the return value on the stack and rely on the runtime call
2022 // to return the value in the same register. We're leaving the code
2023 // managed by the register allocator and tearing down the frame, it's
2024 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002025 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002026 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002027 __ CallRuntime(Runtime::kTraceExit, 1);
2028 }
2029 __ mov(esp, ebp);
2030 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002031 __ Ret((ParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032}
2033
2034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002035void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002036 Register result = ToRegister(instr->result());
2037 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
2038 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002040 DeoptimizeIf(equal, instr->environment());
2041 }
2042}
2043
2044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002045void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2046 ASSERT(ToRegister(instr->context()).is(esi));
2047 ASSERT(ToRegister(instr->global_object()).is(eax));
2048 ASSERT(ToRegister(instr->result()).is(eax));
2049
2050 __ mov(ecx, instr->name());
2051 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2052 RelocInfo::CODE_TARGET_CONTEXT;
2053 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2054 CallCode(ic, mode, instr);
2055}
2056
2057
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002058void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002059 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002060 Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
2061
2062 // If the cell we are storing to contains the hole it could have
2063 // been deleted from the property dictionary. In that case, we need
2064 // to update the property details in the property dictionary to mark
2065 // it as no longer deleted. We deoptimize in that case.
2066 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002067 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002068 DeoptimizeIf(equal, instr->environment());
2069 }
2070
2071 // Store the value.
2072 __ mov(cell_operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002073}
2074
2075
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002076void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002077 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002078 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002079 __ mov(result, ContextOperand(context, instr->slot_index()));
2080}
2081
2082
2083void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2084 Register context = ToRegister(instr->context());
2085 Register value = ToRegister(instr->value());
2086 __ mov(ContextOperand(context, instr->slot_index()), value);
2087 if (instr->needs_write_barrier()) {
2088 Register temp = ToRegister(instr->TempAt(0));
2089 int offset = Context::SlotOffset(instr->slot_index());
2090 __ RecordWrite(context, offset, value, temp);
2091 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002092}
2093
2094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002095void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002096 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002097 Register result = ToRegister(instr->result());
2098 if (instr->hydrogen()->is_in_object()) {
2099 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2100 } else {
2101 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2102 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2103 }
2104}
2105
2106
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002107void LCodeGen::EmitLoadField(Register result,
2108 Register object,
2109 Handle<Map> type,
2110 Handle<String> name) {
2111 LookupResult lookup;
2112 type->LookupInDescriptors(NULL, *name, &lookup);
2113 ASSERT(lookup.IsProperty() && lookup.type() == FIELD);
2114 int index = lookup.GetLocalFieldIndexFromMap(*type);
2115 int offset = index * kPointerSize;
2116 if (index < 0) {
2117 // Negative property indices are in-object properties, indexed
2118 // from the end of the fixed part of the object.
2119 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2120 } else {
2121 // Non-negative property indices are in the properties array.
2122 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2123 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2124 }
2125}
2126
2127
2128void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2129 Register object = ToRegister(instr->object());
2130 Register result = ToRegister(instr->result());
2131
2132 int map_count = instr->hydrogen()->types()->length();
2133 Handle<String> name = instr->hydrogen()->name();
2134 if (map_count == 0) {
2135 ASSERT(instr->hydrogen()->need_generic());
2136 __ mov(ecx, name);
2137 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2138 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
2139 } else {
2140 NearLabel done;
2141 for (int i = 0; i < map_count - 1; ++i) {
2142 Handle<Map> map = instr->hydrogen()->types()->at(i);
2143 NearLabel next;
2144 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2145 __ j(not_equal, &next);
2146 EmitLoadField(result, object, map, name);
2147 __ jmp(&done);
2148 __ bind(&next);
2149 }
2150 Handle<Map> map = instr->hydrogen()->types()->last();
2151 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2152 if (instr->hydrogen()->need_generic()) {
2153 NearLabel generic;
2154 __ j(not_equal, &generic);
2155 EmitLoadField(result, object, map, name);
2156 __ jmp(&done);
2157 __ bind(&generic);
2158 __ mov(ecx, name);
2159 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2160 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
2161 } else {
2162 DeoptimizeIf(not_equal, instr->environment());
2163 EmitLoadField(result, object, map, name);
2164 }
2165 __ bind(&done);
2166 }
2167}
2168
2169
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002171 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002172 ASSERT(ToRegister(instr->object()).is(eax));
2173 ASSERT(ToRegister(instr->result()).is(eax));
2174
2175 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002176 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002177 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2178}
2179
2180
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002181void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2182 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002183 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002184 Register result = ToRegister(instr->result());
2185
2186 // Check that the function really is a function.
2187 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2188 DeoptimizeIf(not_equal, instr->environment());
2189
2190 // Check whether the function has an instance prototype.
2191 NearLabel non_instance;
2192 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2193 1 << Map::kHasNonInstancePrototype);
2194 __ j(not_zero, &non_instance);
2195
2196 // Get the prototype or initial map from the function.
2197 __ mov(result,
2198 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2199
2200 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002202 DeoptimizeIf(equal, instr->environment());
2203
2204 // If the function does not have an initial map, we're done.
2205 NearLabel done;
2206 __ CmpObjectType(result, MAP_TYPE, temp);
2207 __ j(not_equal, &done);
2208
2209 // Get the prototype from the initial map.
2210 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
2211 __ jmp(&done);
2212
2213 // Non-instance prototype: Fetch prototype from constructor field
2214 // in the function's map.
2215 __ bind(&non_instance);
2216 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2217
2218 // All done.
2219 __ bind(&done);
2220}
2221
2222
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002223void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002224 Register result = ToRegister(instr->result());
2225 Register input = ToRegister(instr->InputAt(0));
2226 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002227 if (FLAG_debug_code) {
2228 NearLabel done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002229 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230 Immediate(factory()->fixed_array_map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002231 __ j(equal, &done);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002232 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002233 Immediate(factory()->fixed_cow_array_map()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002234 __ j(equal, &done);
2235 Register temp((result.is(eax)) ? ebx : eax);
2236 __ push(temp);
2237 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
2238 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
2239 __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
2240 __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
2241 __ pop(temp);
2242 __ Check(below, "Check for fast elements or pixel array failed.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002243 __ bind(&done);
2244 }
2245}
2246
2247
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002248void LCodeGen::DoLoadExternalArrayPointer(
2249 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002250 Register result = ToRegister(instr->result());
2251 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002252 __ mov(result, FieldOperand(input,
2253 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002254}
2255
2256
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002257void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2258 Register arguments = ToRegister(instr->arguments());
2259 Register length = ToRegister(instr->length());
2260 Operand index = ToOperand(instr->index());
2261 Register result = ToRegister(instr->result());
2262
2263 __ sub(length, index);
2264 DeoptimizeIf(below_equal, instr->environment());
2265
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002266 // There are two words between the frame pointer and the last argument.
2267 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002268 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2269}
2270
2271
2272void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
2273 Register elements = ToRegister(instr->elements());
2274 Register key = ToRegister(instr->key());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002275 Register result = ToRegister(instr->result());
2276 ASSERT(result.is(elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002277
2278 // Load the result.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002279 __ mov(result, FieldOperand(elements,
2280 key,
2281 times_pointer_size,
2282 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002283
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002284 // Check for the hole value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 __ cmp(result, factory()->the_hole_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002286 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002287}
2288
2289
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002290void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2291 LLoadKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002292 Register external_pointer = ToRegister(instr->external_pointer());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002293 Register key = ToRegister(instr->key());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002294 ExternalArrayType array_type = instr->array_type();
2295 if (array_type == kExternalFloatArray) {
2296 XMMRegister result(ToDoubleRegister(instr->result()));
2297 __ movss(result, Operand(external_pointer, key, times_4, 0));
2298 __ cvtss2sd(result, result);
2299 } else {
2300 Register result(ToRegister(instr->result()));
2301 switch (array_type) {
2302 case kExternalByteArray:
2303 __ movsx_b(result, Operand(external_pointer, key, times_1, 0));
2304 break;
2305 case kExternalUnsignedByteArray:
2306 case kExternalPixelArray:
2307 __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
2308 break;
2309 case kExternalShortArray:
2310 __ movsx_w(result, Operand(external_pointer, key, times_2, 0));
2311 break;
2312 case kExternalUnsignedShortArray:
2313 __ movzx_w(result, Operand(external_pointer, key, times_2, 0));
2314 break;
2315 case kExternalIntArray:
2316 __ mov(result, Operand(external_pointer, key, times_4, 0));
2317 break;
2318 case kExternalUnsignedIntArray:
2319 __ mov(result, Operand(external_pointer, key, times_4, 0));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002320 __ test(result, Operand(result));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002321 // TODO(danno): we could be more clever here, perhaps having a special
2322 // version of the stub that detects if the overflow case actually
2323 // happens, and generate code that returns a double rather than int.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002324 DeoptimizeIf(negative, instr->environment());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002325 break;
2326 case kExternalFloatArray:
2327 UNREACHABLE();
2328 break;
2329 }
2330 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002331}
2332
2333
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002335 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002336 ASSERT(ToRegister(instr->object()).is(edx));
2337 ASSERT(ToRegister(instr->key()).is(eax));
2338
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002339 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002340 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2341}
2342
2343
2344void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2345 Register result = ToRegister(instr->result());
2346
2347 // Check for arguments adapter frame.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002348 NearLabel done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002349 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2350 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2351 __ cmp(Operand(result),
2352 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2353 __ j(equal, &adapted);
2354
2355 // No arguments adaptor frame.
2356 __ mov(result, Operand(ebp));
2357 __ jmp(&done);
2358
2359 // Arguments adaptor frame present.
2360 __ bind(&adapted);
2361 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2362
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002363 // Result is the frame pointer for the frame if not adapted and for the real
2364 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002365 __ bind(&done);
2366}
2367
2368
2369void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002370 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002371 Register result = ToRegister(instr->result());
2372
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002373 NearLabel done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002374
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002375 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002376 __ cmp(ebp, elem);
2377 __ mov(result, Immediate(scope()->num_parameters()));
2378 __ j(equal, &done);
2379
2380 // Arguments adaptor frame present. Get argument length from there.
2381 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2382 __ mov(result, Operand(result,
2383 ArgumentsAdaptorFrameConstants::kLengthOffset));
2384 __ SmiUntag(result);
2385
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002386 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002387 __ bind(&done);
2388}
2389
2390
2391void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2392 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002393 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002394 Register length = ToRegister(instr->length());
2395 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002396 Register scratch = ToRegister(instr->TempAt(0));
2397 ASSERT(receiver.is(eax)); // Used for parameter count.
2398 ASSERT(function.is(edi)); // Required by InvokeFunction.
2399 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002400
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002401 // If the receiver is null or undefined, we have to pass the global object
2402 // as a receiver.
2403 NearLabel global_object, receiver_ok;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002404 __ cmp(receiver, factory()->null_value());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002405 __ j(equal, &global_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002406 __ cmp(receiver, factory()->undefined_value());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002407 __ j(equal, &global_object);
2408
2409 // The receiver should be a JS object.
2410 __ test(receiver, Immediate(kSmiTagMask));
2411 DeoptimizeIf(equal, instr->environment());
2412 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch);
2413 DeoptimizeIf(below, instr->environment());
2414 __ jmp(&receiver_ok);
2415
2416 __ bind(&global_object);
2417 // TODO(kmillikin): We have a hydrogen value for the global object. See
2418 // if it's better to use it than to explicitly fetch it from the context
2419 // here.
2420 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2421 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
2422 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002423
2424 // Copy the arguments to this function possibly from the
2425 // adaptor frame below it.
2426 const uint32_t kArgumentsLimit = 1 * KB;
2427 __ cmp(length, kArgumentsLimit);
2428 DeoptimizeIf(above, instr->environment());
2429
2430 __ push(receiver);
2431 __ mov(receiver, length);
2432
2433 // Loop through the arguments pushing them onto the execution
2434 // stack.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002435 NearLabel invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002436 // length is a small non-negative integer, due to the test above.
2437 __ test(length, Operand(length));
2438 __ j(zero, &invoke);
2439 __ bind(&loop);
2440 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2441 __ dec(length);
2442 __ j(not_zero, &loop);
2443
2444 // Invoke the function.
2445 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002446 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2447 LPointerMap* pointers = instr->pointer_map();
2448 LEnvironment* env = instr->deoptimization_environment();
2449 RecordPosition(pointers->position());
2450 RegisterEnvironmentForDeoptimization(env);
2451 SafepointGenerator safepoint_generator(this,
2452 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002453 env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002454 v8::internal::ParameterCount actual(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002455 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002456}
2457
2458
2459void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002460 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002461 if (argument->IsConstantOperand()) {
2462 __ push(ToImmediate(argument));
2463 } else {
2464 __ push(ToOperand(argument));
2465 }
2466}
2467
2468
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002469void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002470 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002471 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002472}
2473
2474
2475void LCodeGen::DoOuterContext(LOuterContext* instr) {
2476 Register context = ToRegister(instr->context());
2477 Register result = ToRegister(instr->result());
2478 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2479 __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
2480}
2481
2482
2483void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2484 Register context = ToRegister(instr->context());
2485 Register result = ToRegister(instr->result());
2486 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002487}
2488
2489
2490void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002491 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002493 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002494}
2495
2496
2497void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2498 int arity,
2499 LInstruction* instr) {
2500 // Change context if needed.
2501 bool change_context =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002502 (info()->closure()->context() != function->context()) ||
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 scope()->contains_with() ||
2504 (scope()->num_heap_slots() > 0);
2505 if (change_context) {
2506 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002507 } else {
2508 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002509 }
2510
2511 // Set eax to arguments count if adaption is not needed. Assumes that eax
2512 // is available to write to at this point.
2513 if (!function->NeedsArgumentsAdaption()) {
2514 __ mov(eax, arity);
2515 }
2516
2517 LPointerMap* pointers = instr->pointer_map();
2518 RecordPosition(pointers->position());
2519
2520 // Invoke function.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002521 if (*function == *info()->closure()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002522 __ CallSelf();
2523 } else {
2524 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2525 }
2526
2527 // Setup deoptimization.
2528 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002529}
2530
2531
2532void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2533 ASSERT(ToRegister(instr->result()).is(eax));
2534 __ mov(edi, instr->function());
2535 CallKnownFunction(instr->function(), instr->arity(), instr);
2536}
2537
2538
2539void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002540 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002541 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002542 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002543 DeoptimizeIf(not_equal, instr->environment());
2544
2545 Label done;
2546 Register tmp = input_reg.is(eax) ? ecx : eax;
2547 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2548
2549 // Preserve the value of all registers.
2550 __ PushSafepointRegisters();
2551
2552 Label negative;
2553 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002554 // Check the sign of the argument. If the argument is positive, just
2555 // return it. We do not need to patch the stack since |input| and
2556 // |result| are the same register and |input| will be restored
2557 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002558 __ test(tmp, Immediate(HeapNumber::kSignMask));
2559 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002560 __ jmp(&done);
2561
2562 __ bind(&negative);
2563
2564 Label allocated, slow;
2565 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2566 __ jmp(&allocated);
2567
2568 // Slow case: Call the runtime system to do the number allocation.
2569 __ bind(&slow);
2570
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002571 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002572 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
2573 RecordSafepointWithRegisters(
2574 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
2575 // Set the pointer to the new heap number in tmp.
2576 if (!tmp.is(eax)) __ mov(tmp, eax);
2577
2578 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002579 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002580
2581 __ bind(&allocated);
2582 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2583 __ and_(tmp2, ~HeapNumber::kSignMask);
2584 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2585 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2586 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002587 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002588
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002589 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002590 __ PopSafepointRegisters();
2591}
2592
2593
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002594void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2595 Register input_reg = ToRegister(instr->InputAt(0));
2596 __ test(input_reg, Operand(input_reg));
2597 Label is_positive;
2598 __ j(not_sign, &is_positive);
2599 __ neg(input_reg);
2600 __ test(input_reg, Operand(input_reg));
2601 DeoptimizeIf(negative, instr->environment());
2602 __ bind(&is_positive);
2603}
2604
2605
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002606void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2607 // Class for deferred case.
2608 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2609 public:
2610 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2611 LUnaryMathOperation* instr)
2612 : LDeferredCode(codegen), instr_(instr) { }
2613 virtual void Generate() {
2614 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2615 }
2616 private:
2617 LUnaryMathOperation* instr_;
2618 };
2619
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002620 ASSERT(instr->InputAt(0)->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002621 Representation r = instr->hydrogen()->value()->representation();
2622
2623 if (r.IsDouble()) {
2624 XMMRegister scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002625 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002626 __ pxor(scratch, scratch);
2627 __ subsd(scratch, input_reg);
2628 __ pand(input_reg, scratch);
2629 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002630 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002631 } else { // Tagged case.
2632 DeferredMathAbsTaggedHeapNumber* deferred =
2633 new DeferredMathAbsTaggedHeapNumber(this, instr);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002634 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002635 // Smi check.
2636 __ test(input_reg, Immediate(kSmiTagMask));
2637 __ j(not_zero, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002638 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002639 __ bind(deferred->exit());
2640 }
2641}
2642
2643
2644void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2645 XMMRegister xmm_scratch = xmm0;
2646 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002647 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002648 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2649 __ ucomisd(input_reg, xmm_scratch);
2650
2651 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2652 DeoptimizeIf(below_equal, instr->environment());
2653 } else {
2654 DeoptimizeIf(below, instr->environment());
2655 }
2656
2657 // Use truncating instruction (OK because input is positive).
2658 __ cvttsd2si(output_reg, Operand(input_reg));
2659
2660 // Overflow is signalled with minint.
2661 __ cmp(output_reg, 0x80000000u);
2662 DeoptimizeIf(equal, instr->environment());
2663}
2664
2665
2666void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2667 XMMRegister xmm_scratch = xmm0;
2668 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002669 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002670
2671 // xmm_scratch = 0.5
2672 ExternalReference one_half = ExternalReference::address_of_one_half();
2673 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
2674
2675 // input = input + 0.5
2676 __ addsd(input_reg, xmm_scratch);
2677
2678 // We need to return -0 for the input range [-0.5, 0[, otherwise
2679 // compute Math.floor(value + 0.5).
2680 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2681 __ ucomisd(input_reg, xmm_scratch);
2682 DeoptimizeIf(below_equal, instr->environment());
2683 } else {
2684 // If we don't need to bailout on -0, we check only bailout
2685 // on negative inputs.
2686 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2687 __ ucomisd(input_reg, xmm_scratch);
2688 DeoptimizeIf(below, instr->environment());
2689 }
2690
2691 // Compute Math.floor(value + 0.5).
2692 // Use truncating instruction (OK because input is positive).
2693 __ cvttsd2si(output_reg, Operand(input_reg));
2694
2695 // Overflow is signalled with minint.
2696 __ cmp(output_reg, 0x80000000u);
2697 DeoptimizeIf(equal, instr->environment());
2698}
2699
2700
2701void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002702 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002703 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2704 __ sqrtsd(input_reg, input_reg);
2705}
2706
2707
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002708void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2709 XMMRegister xmm_scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002710 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002711 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002712 __ xorpd(xmm_scratch, xmm_scratch);
2713 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002714 __ sqrtsd(input_reg, input_reg);
2715}
2716
2717
2718void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002719 LOperand* left = instr->InputAt(0);
2720 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002721 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2722 Representation exponent_type = instr->hydrogen()->right()->representation();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002724 if (exponent_type.IsDouble()) {
2725 // It is safe to use ebx directly since the instruction is marked
2726 // as a call.
2727 __ PrepareCallCFunction(4, ebx);
2728 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2729 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002730 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2731 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002732 } else if (exponent_type.IsInteger32()) {
2733 // It is safe to use ebx directly since the instruction is marked
2734 // as a call.
2735 ASSERT(!ToRegister(right).is(ebx));
2736 __ PrepareCallCFunction(4, ebx);
2737 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2738 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002739 __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
2740 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002741 } else {
2742 ASSERT(exponent_type.IsTagged());
2743 CpuFeatures::Scope scope(SSE2);
2744 Register right_reg = ToRegister(right);
2745
2746 Label non_smi, call;
2747 __ test(right_reg, Immediate(kSmiTagMask));
2748 __ j(not_zero, &non_smi);
2749 __ SmiUntag(right_reg);
2750 __ cvtsi2sd(result_reg, Operand(right_reg));
2751 __ jmp(&call);
2752
2753 __ bind(&non_smi);
2754 // It is safe to use ebx directly since the instruction is marked
2755 // as a call.
2756 ASSERT(!right_reg.is(ebx));
2757 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
2758 DeoptimizeIf(not_equal, instr->environment());
2759 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
2760
2761 __ bind(&call);
2762 __ PrepareCallCFunction(4, ebx);
2763 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2764 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002765 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2766 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002767 }
2768
2769 // Return value is in st(0) on ia32.
2770 // Store it into the (fixed) result register.
2771 __ sub(Operand(esp), Immediate(kDoubleSize));
2772 __ fstp_d(Operand(esp, 0));
2773 __ movdbl(result_reg, Operand(esp, 0));
2774 __ add(Operand(esp), Immediate(kDoubleSize));
2775}
2776
2777
2778void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
2779 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002780 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2781 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002782 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002783}
2784
2785
2786void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
2787 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2788 TranscendentalCacheStub stub(TranscendentalCache::COS,
2789 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002790 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002791}
2792
2793
2794void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
2795 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2796 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2797 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002798 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002799}
2800
2801
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002802void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
2803 switch (instr->op()) {
2804 case kMathAbs:
2805 DoMathAbs(instr);
2806 break;
2807 case kMathFloor:
2808 DoMathFloor(instr);
2809 break;
2810 case kMathRound:
2811 DoMathRound(instr);
2812 break;
2813 case kMathSqrt:
2814 DoMathSqrt(instr);
2815 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002816 case kMathPowHalf:
2817 DoMathPowHalf(instr);
2818 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00002819 case kMathCos:
2820 DoMathCos(instr);
2821 break;
2822 case kMathSin:
2823 DoMathSin(instr);
2824 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002825 case kMathLog:
2826 DoMathLog(instr);
2827 break;
2828
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002829 default:
2830 UNREACHABLE();
2831 }
2832}
2833
2834
2835void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002836 ASSERT(ToRegister(instr->context()).is(esi));
2837 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002838 ASSERT(ToRegister(instr->result()).is(eax));
2839
2840 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002841 Handle<Code> ic = isolate()->stub_cache()->
2842 ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002843 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002844}
2845
2846
2847void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002848 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002849 ASSERT(ToRegister(instr->result()).is(eax));
2850
2851 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002852 Handle<Code> ic = isolate()->stub_cache()->
2853 ComputeCallInitialize(arity, NOT_IN_LOOP);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002854 __ mov(ecx, instr->name());
2855 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002856}
2857
2858
2859void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002860 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002861 ASSERT(ToRegister(instr->result()).is(eax));
2862
2863 int arity = instr->arity();
2864 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
2865 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2866 __ Drop(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002867}
2868
2869
2870void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002871 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002872 ASSERT(ToRegister(instr->result()).is(eax));
2873
2874 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002875 Handle<Code> ic = isolate()->stub_cache()->
2876 ComputeCallInitialize(arity, NOT_IN_LOOP);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877 __ mov(ecx, instr->name());
2878 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002879}
2880
2881
2882void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
2883 ASSERT(ToRegister(instr->result()).is(eax));
2884 __ mov(edi, instr->target());
2885 CallKnownFunction(instr->target(), instr->arity(), instr);
2886}
2887
2888
2889void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002890 ASSERT(ToRegister(instr->context()).is(esi));
2891 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002892 ASSERT(ToRegister(instr->result()).is(eax));
2893
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002894 Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002895 __ Set(eax, Immediate(instr->arity()));
2896 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
2897}
2898
2899
2900void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002901 CallRuntime(instr->function(), instr->arity(), instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002902}
2903
2904
2905void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
2906 Register object = ToRegister(instr->object());
2907 Register value = ToRegister(instr->value());
2908 int offset = instr->offset();
2909
2910 if (!instr->transition().is_null()) {
2911 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
2912 }
2913
2914 // Do the store.
2915 if (instr->is_in_object()) {
2916 __ mov(FieldOperand(object, offset), value);
2917 if (instr->needs_write_barrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002918 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002919 // Update the write barrier for the object for in-object properties.
2920 __ RecordWrite(object, offset, value, temp);
2921 }
2922 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002923 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002924 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
2925 __ mov(FieldOperand(temp, offset), value);
2926 if (instr->needs_write_barrier()) {
2927 // Update the write barrier for the properties array.
2928 // object is used as a scratch register.
2929 __ RecordWrite(temp, offset, value, object);
2930 }
2931 }
2932}
2933
2934
2935void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002936 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002937 ASSERT(ToRegister(instr->object()).is(edx));
2938 ASSERT(ToRegister(instr->value()).is(eax));
2939
2940 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002941 Handle<Code> ic = info_->is_strict()
2942 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2943 : isolate()->builtins()->StoreIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2945}
2946
2947
2948void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
2949 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
2950 DeoptimizeIf(above_equal, instr->environment());
2951}
2952
2953
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002954void LCodeGen::DoStoreKeyedSpecializedArrayElement(
2955 LStoreKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002956 Register external_pointer = ToRegister(instr->external_pointer());
2957 Register key = ToRegister(instr->key());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002958 ExternalArrayType array_type = instr->array_type();
2959 if (array_type == kExternalFloatArray) {
2960 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
2961 __ movss(Operand(external_pointer, key, times_4, 0), xmm0);
2962 } else {
2963 Register value = ToRegister(instr->value());
2964 switch (array_type) {
2965 case kExternalPixelArray: {
2966 // Clamp the value to [0..255].
2967 Register temp = ToRegister(instr->TempAt(0));
2968 // The dec_b below requires that the clamped value is in a byte
2969 // register. eax is an arbitrary choice to satisfy this requirement, we
2970 // hinted the register allocator to give us eax when building the
2971 // instruction.
2972 ASSERT(temp.is(eax));
2973 __ mov(temp, ToRegister(instr->value()));
2974 NearLabel done;
2975 __ test(temp, Immediate(0xFFFFFF00));
2976 __ j(zero, &done);
2977 __ setcc(negative, temp); // 1 if negative, 0 if positive.
2978 __ dec_b(temp); // 0 if negative, 255 if positive.
2979 __ bind(&done);
2980 __ mov_b(Operand(external_pointer, key, times_1, 0), temp);
2981 break;
2982 }
2983 case kExternalByteArray:
2984 case kExternalUnsignedByteArray:
2985 __ mov_b(Operand(external_pointer, key, times_1, 0), value);
2986 break;
2987 case kExternalShortArray:
2988 case kExternalUnsignedShortArray:
2989 __ mov_w(Operand(external_pointer, key, times_2, 0), value);
2990 break;
2991 case kExternalIntArray:
2992 case kExternalUnsignedIntArray:
2993 __ mov(Operand(external_pointer, key, times_4, 0), value);
2994 break;
2995 case kExternalFloatArray:
2996 UNREACHABLE();
2997 break;
2998 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002999 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003000}
3001
3002
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003003void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3004 Register value = ToRegister(instr->value());
3005 Register elements = ToRegister(instr->object());
3006 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3007
3008 // Do the store.
3009 if (instr->key()->IsConstantOperand()) {
3010 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3011 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3012 int offset =
3013 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3014 __ mov(FieldOperand(elements, offset), value);
3015 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003016 __ mov(FieldOperand(elements,
3017 key,
3018 times_pointer_size,
3019 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003020 value);
3021 }
3022
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003023 if (instr->hydrogen()->NeedsWriteBarrier()) {
3024 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003025 __ lea(key,
3026 FieldOperand(elements,
3027 key,
3028 times_pointer_size,
3029 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003030 __ RecordWrite(elements, key, value);
3031 }
3032}
3033
3034
3035void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003036 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003037 ASSERT(ToRegister(instr->object()).is(edx));
3038 ASSERT(ToRegister(instr->key()).is(ecx));
3039 ASSERT(ToRegister(instr->value()).is(eax));
3040
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003041 Handle<Code> ic = info_->is_strict()
3042 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3043 : isolate()->builtins()->KeyedStoreIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003044 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3045}
3046
3047
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003048void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3049 class DeferredStringCharCodeAt: public LDeferredCode {
3050 public:
3051 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3052 : LDeferredCode(codegen), instr_(instr) { }
3053 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
3054 private:
3055 LStringCharCodeAt* instr_;
3056 };
3057
3058 Register string = ToRegister(instr->string());
3059 Register index = no_reg;
3060 int const_index = -1;
3061 if (instr->index()->IsConstantOperand()) {
3062 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3063 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3064 if (!Smi::IsValid(const_index)) {
3065 // Guaranteed to be out of bounds because of the assert above.
3066 // So the bounds check that must dominate this instruction must
3067 // have deoptimized already.
3068 if (FLAG_debug_code) {
3069 __ Abort("StringCharCodeAt: out of bounds index.");
3070 }
3071 // No code needs to be generated.
3072 return;
3073 }
3074 } else {
3075 index = ToRegister(instr->index());
3076 }
3077 Register result = ToRegister(instr->result());
3078
3079 DeferredStringCharCodeAt* deferred =
3080 new DeferredStringCharCodeAt(this, instr);
3081
3082 NearLabel flat_string, ascii_string, done;
3083
3084 // Fetch the instance type of the receiver into result register.
3085 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3086 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3087
3088 // We need special handling for non-flat strings.
3089 STATIC_ASSERT(kSeqStringTag == 0);
3090 __ test(result, Immediate(kStringRepresentationMask));
3091 __ j(zero, &flat_string);
3092
3093 // Handle non-flat strings.
3094 __ test(result, Immediate(kIsConsStringMask));
3095 __ j(zero, deferred->entry());
3096
3097 // ConsString.
3098 // Check whether the right hand side is the empty string (i.e. if
3099 // this is really a flat string in a cons string). If that is not
3100 // the case we would rather go to the runtime system now to flatten
3101 // the string.
3102 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003103 Immediate(factory()->empty_string()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003104 __ j(not_equal, deferred->entry());
3105 // Get the first of the two strings and load its instance type.
3106 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
3107 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3108 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3109 // If the first cons component is also non-flat, then go to runtime.
3110 STATIC_ASSERT(kSeqStringTag == 0);
3111 __ test(result, Immediate(kStringRepresentationMask));
3112 __ j(not_zero, deferred->entry());
3113
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003114 // Check for ASCII or two-byte string.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003115 __ bind(&flat_string);
3116 STATIC_ASSERT(kAsciiStringTag != 0);
3117 __ test(result, Immediate(kStringEncodingMask));
3118 __ j(not_zero, &ascii_string);
3119
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003120 // Two-byte string.
3121 // Load the two-byte character code into the result register.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003122 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3123 if (instr->index()->IsConstantOperand()) {
3124 __ movzx_w(result,
3125 FieldOperand(string,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003126 SeqTwoByteString::kHeaderSize +
3127 (kUC16Size * const_index)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003128 } else {
3129 __ movzx_w(result, FieldOperand(string,
3130 index,
3131 times_2,
3132 SeqTwoByteString::kHeaderSize));
3133 }
3134 __ jmp(&done);
3135
3136 // ASCII string.
3137 // Load the byte into the result register.
3138 __ bind(&ascii_string);
3139 if (instr->index()->IsConstantOperand()) {
3140 __ movzx_b(result, FieldOperand(string,
3141 SeqAsciiString::kHeaderSize + const_index));
3142 } else {
3143 __ movzx_b(result, FieldOperand(string,
3144 index,
3145 times_1,
3146 SeqAsciiString::kHeaderSize));
3147 }
3148 __ bind(&done);
3149 __ bind(deferred->exit());
3150}
3151
3152
3153void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3154 Register string = ToRegister(instr->string());
3155 Register result = ToRegister(instr->result());
3156
3157 // TODO(3095996): Get rid of this. For now, we need to make the
3158 // result register contain a valid pointer because it is already
3159 // contained in the register pointer map.
3160 __ Set(result, Immediate(0));
3161
3162 __ PushSafepointRegisters();
3163 __ push(string);
3164 // Push the index as a smi. This is safe because of the checks in
3165 // DoStringCharCodeAt above.
3166 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3167 if (instr->index()->IsConstantOperand()) {
3168 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3169 __ push(Immediate(Smi::FromInt(const_index)));
3170 } else {
3171 Register index = ToRegister(instr->index());
3172 __ SmiTag(index);
3173 __ push(index);
3174 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003175 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003176 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
3177 RecordSafepointWithRegisters(
3178 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
3179 if (FLAG_debug_code) {
3180 __ AbortIfNotSmi(eax);
3181 }
3182 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003183 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003184 __ PopSafepointRegisters();
3185}
3186
3187
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003188void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3189 class DeferredStringCharFromCode: public LDeferredCode {
3190 public:
3191 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3192 : LDeferredCode(codegen), instr_(instr) { }
3193 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
3194 private:
3195 LStringCharFromCode* instr_;
3196 };
3197
3198 DeferredStringCharFromCode* deferred =
3199 new DeferredStringCharFromCode(this, instr);
3200
3201 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3202 Register char_code = ToRegister(instr->char_code());
3203 Register result = ToRegister(instr->result());
3204 ASSERT(!char_code.is(result));
3205
3206 __ cmp(char_code, String::kMaxAsciiCharCode);
3207 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003208 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003209 __ mov(result, FieldOperand(result,
3210 char_code, times_pointer_size,
3211 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003212 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003213 __ j(equal, deferred->entry());
3214 __ bind(deferred->exit());
3215}
3216
3217
3218void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3219 Register char_code = ToRegister(instr->char_code());
3220 Register result = ToRegister(instr->result());
3221
3222 // TODO(3095996): Get rid of this. For now, we need to make the
3223 // result register contain a valid pointer because it is already
3224 // contained in the register pointer map.
3225 __ Set(result, Immediate(0));
3226
3227 __ PushSafepointRegisters();
3228 __ SmiTag(char_code);
3229 __ push(char_code);
3230 __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
3231 RecordSafepointWithRegisters(
3232 instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
3233 __ StoreToSafepointRegisterSlot(result, eax);
3234 __ PopSafepointRegisters();
3235}
3236
3237
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003238void LCodeGen::DoStringLength(LStringLength* instr) {
3239 Register string = ToRegister(instr->string());
3240 Register result = ToRegister(instr->result());
3241 __ mov(result, FieldOperand(string, String::kLengthOffset));
3242}
3243
3244
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003245void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003246 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003247 ASSERT(input->IsRegister() || input->IsStackSlot());
3248 LOperand* output = instr->result();
3249 ASSERT(output->IsDoubleRegister());
3250 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3251}
3252
3253
3254void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3255 class DeferredNumberTagI: public LDeferredCode {
3256 public:
3257 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3258 : LDeferredCode(codegen), instr_(instr) { }
3259 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
3260 private:
3261 LNumberTagI* instr_;
3262 };
3263
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003264 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003265 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3266 Register reg = ToRegister(input);
3267
3268 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3269 __ SmiTag(reg);
3270 __ j(overflow, deferred->entry());
3271 __ bind(deferred->exit());
3272}
3273
3274
3275void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3276 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003277 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003278 Register tmp = reg.is(eax) ? ecx : eax;
3279
3280 // Preserve the value of all registers.
3281 __ PushSafepointRegisters();
3282
3283 // There was overflow, so bits 30 and 31 of the original integer
3284 // disagree. Try to allocate a heap number in new space and store
3285 // the value in there. If that fails, call the runtime system.
3286 NearLabel done;
3287 __ SmiUntag(reg);
3288 __ xor_(reg, 0x80000000);
3289 __ cvtsi2sd(xmm0, Operand(reg));
3290 if (FLAG_inline_new) {
3291 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
3292 __ jmp(&done);
3293 }
3294
3295 // Slow case: Call the runtime system to do the number allocation.
3296 __ bind(&slow);
3297
3298 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3299 // register is stored, as this register is in the pointer map, but contains an
3300 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003301 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003302
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003303 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003304 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3305 RecordSafepointWithRegisters(
3306 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
3307 if (!reg.is(eax)) __ mov(reg, eax);
3308
3309 // Done. Put the value in xmm0 into the value of the allocated heap
3310 // number.
3311 __ bind(&done);
3312 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003313 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003314 __ PopSafepointRegisters();
3315}
3316
3317
3318void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3319 class DeferredNumberTagD: public LDeferredCode {
3320 public:
3321 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3322 : LDeferredCode(codegen), instr_(instr) { }
3323 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
3324 private:
3325 LNumberTagD* instr_;
3326 };
3327
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003328 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003329 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003330 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003331
3332 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3333 if (FLAG_inline_new) {
3334 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3335 } else {
3336 __ jmp(deferred->entry());
3337 }
3338 __ bind(deferred->exit());
3339 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3340}
3341
3342
3343void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3344 // TODO(3095996): Get rid of this. For now, we need to make the
3345 // result register contain a valid pointer because it is already
3346 // contained in the register pointer map.
3347 Register reg = ToRegister(instr->result());
3348 __ Set(reg, Immediate(0));
3349
3350 __ PushSafepointRegisters();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003351 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003352 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3353 RecordSafepointWithRegisters(
3354 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003355 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003356 __ PopSafepointRegisters();
3357}
3358
3359
3360void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003361 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003362 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3363 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3364 __ SmiTag(ToRegister(input));
3365}
3366
3367
3368void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003369 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003370 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3371 if (instr->needs_check()) {
3372 __ test(ToRegister(input), Immediate(kSmiTagMask));
3373 DeoptimizeIf(not_zero, instr->environment());
3374 }
3375 __ SmiUntag(ToRegister(input));
3376}
3377
3378
3379void LCodeGen::EmitNumberUntagD(Register input_reg,
3380 XMMRegister result_reg,
3381 LEnvironment* env) {
3382 NearLabel load_smi, heap_number, done;
3383
3384 // Smi check.
3385 __ test(input_reg, Immediate(kSmiTagMask));
3386 __ j(zero, &load_smi, not_taken);
3387
3388 // Heap number map check.
3389 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003390 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003391 __ j(equal, &heap_number);
3392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003394 DeoptimizeIf(not_equal, env);
3395
3396 // Convert undefined to NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003397 ExternalReference nan = ExternalReference::address_of_nan();
3398 __ movdbl(result_reg, Operand::StaticVariable(nan));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003399 __ jmp(&done);
3400
3401 // Heap number to XMM conversion.
3402 __ bind(&heap_number);
3403 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3404 __ jmp(&done);
3405
3406 // Smi to XMM conversion
3407 __ bind(&load_smi);
3408 __ SmiUntag(input_reg); // Untag smi before converting to float.
3409 __ cvtsi2sd(result_reg, Operand(input_reg));
3410 __ SmiTag(input_reg); // Retag smi.
3411 __ bind(&done);
3412}
3413
3414
3415class DeferredTaggedToI: public LDeferredCode {
3416 public:
3417 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3418 : LDeferredCode(codegen), instr_(instr) { }
3419 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3420 private:
3421 LTaggedToI* instr_;
3422};
3423
3424
3425void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
3426 NearLabel done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003427 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003428
3429 // Heap number map check.
3430 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003431 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003432
3433 if (instr->truncating()) {
3434 __ j(equal, &heap_number);
3435 // Check for undefined. Undefined is converted to zero for truncating
3436 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003437 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003438 DeoptimizeIf(not_equal, instr->environment());
3439 __ mov(input_reg, 0);
3440 __ jmp(&done);
3441
3442 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003443 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003444 CpuFeatures::Scope scope(SSE3);
3445 NearLabel convert;
3446 // Use more powerful conversion when sse3 is available.
3447 // Load x87 register with heap number.
3448 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3449 // Get exponent alone and check for too-big exponent.
3450 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3451 __ and_(input_reg, HeapNumber::kExponentMask);
3452 const uint32_t kTooBigExponent =
3453 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3454 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
3455 __ j(less, &convert);
3456 // Pop FPU stack before deoptimizing.
3457 __ ffree(0);
3458 __ fincstp();
3459 DeoptimizeIf(no_condition, instr->environment());
3460
3461 // Reserve space for 64 bit answer.
3462 __ bind(&convert);
3463 __ sub(Operand(esp), Immediate(kDoubleSize));
3464 // Do conversion, which cannot fail because we checked the exponent.
3465 __ fisttp_d(Operand(esp, 0));
3466 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3467 __ add(Operand(esp), Immediate(kDoubleSize));
3468 } else {
3469 NearLabel deopt;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003470 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003471 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3472 __ cvttsd2si(input_reg, Operand(xmm0));
3473 __ cmp(input_reg, 0x80000000u);
3474 __ j(not_equal, &done);
3475 // Check if the input was 0x8000000 (kMinInt).
3476 // If no, then we got an overflow and we deoptimize.
3477 ExternalReference min_int = ExternalReference::address_of_min_int();
3478 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3479 __ ucomisd(xmm_temp, xmm0);
3480 DeoptimizeIf(not_equal, instr->environment());
3481 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3482 }
3483 } else {
3484 // Deoptimize if we don't have a heap number.
3485 DeoptimizeIf(not_equal, instr->environment());
3486
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003487 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003488 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3489 __ cvttsd2si(input_reg, Operand(xmm0));
3490 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3491 __ ucomisd(xmm0, xmm_temp);
3492 DeoptimizeIf(not_equal, instr->environment());
3493 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3494 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3495 __ test(input_reg, Operand(input_reg));
3496 __ j(not_zero, &done);
3497 __ movmskpd(input_reg, xmm0);
3498 __ and_(input_reg, 1);
3499 DeoptimizeIf(not_zero, instr->environment());
3500 }
3501 }
3502 __ bind(&done);
3503}
3504
3505
3506void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003507 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003508 ASSERT(input->IsRegister());
3509 ASSERT(input->Equals(instr->result()));
3510
3511 Register input_reg = ToRegister(input);
3512
3513 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3514
3515 // Smi check.
3516 __ test(input_reg, Immediate(kSmiTagMask));
3517 __ j(not_zero, deferred->entry());
3518
3519 // Smi to int32 conversion
3520 __ SmiUntag(input_reg); // Untag smi.
3521
3522 __ bind(deferred->exit());
3523}
3524
3525
3526void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003527 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003528 ASSERT(input->IsRegister());
3529 LOperand* result = instr->result();
3530 ASSERT(result->IsDoubleRegister());
3531
3532 Register input_reg = ToRegister(input);
3533 XMMRegister result_reg = ToDoubleRegister(result);
3534
3535 EmitNumberUntagD(input_reg, result_reg, instr->environment());
3536}
3537
3538
3539void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003540 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003541 ASSERT(input->IsDoubleRegister());
3542 LOperand* result = instr->result();
3543 ASSERT(result->IsRegister());
3544
3545 XMMRegister input_reg = ToDoubleRegister(input);
3546 Register result_reg = ToRegister(result);
3547
3548 if (instr->truncating()) {
3549 // Performs a truncating conversion of a floating point number as used by
3550 // the JS bitwise operations.
3551 __ cvttsd2si(result_reg, Operand(input_reg));
3552 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003553 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003554 // This will deoptimize if the exponent of the input in out of range.
3555 CpuFeatures::Scope scope(SSE3);
3556 NearLabel convert, done;
3557 __ j(not_equal, &done);
3558 __ sub(Operand(esp), Immediate(kDoubleSize));
3559 __ movdbl(Operand(esp, 0), input_reg);
3560 // Get exponent alone and check for too-big exponent.
3561 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3562 __ and_(result_reg, HeapNumber::kExponentMask);
3563 const uint32_t kTooBigExponent =
3564 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3565 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
3566 __ j(less, &convert);
3567 __ add(Operand(esp), Immediate(kDoubleSize));
3568 DeoptimizeIf(no_condition, instr->environment());
3569 __ bind(&convert);
3570 // Do conversion, which cannot fail because we checked the exponent.
3571 __ fld_d(Operand(esp, 0));
3572 __ fisttp_d(Operand(esp, 0));
3573 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3574 __ add(Operand(esp), Immediate(kDoubleSize));
3575 __ bind(&done);
3576 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003577 NearLabel done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003578 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003579 XMMRegister xmm_scratch = xmm0;
3580
3581 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3582 // manual conversion.
3583 __ j(not_equal, &done);
3584
3585 // Get high 32 bits of the input in result_reg and temp_reg.
3586 __ pshufd(xmm_scratch, input_reg, 1);
3587 __ movd(Operand(temp_reg), xmm_scratch);
3588 __ mov(result_reg, temp_reg);
3589
3590 // Prepare negation mask in temp_reg.
3591 __ sar(temp_reg, kBitsPerInt - 1);
3592
3593 // Extract the exponent from result_reg and subtract adjusted
3594 // bias from it. The adjustment is selected in a way such that
3595 // when the difference is zero, the answer is in the low 32 bits
3596 // of the input, otherwise a shift has to be performed.
3597 __ shr(result_reg, HeapNumber::kExponentShift);
3598 __ and_(result_reg,
3599 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3600 __ sub(Operand(result_reg),
3601 Immediate(HeapNumber::kExponentBias +
3602 HeapNumber::kExponentBits +
3603 HeapNumber::kMantissaBits));
3604 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3605 // special exponents.
3606 DeoptimizeIf(greater, instr->environment());
3607
3608 // Zero out the sign and the exponent in the input (by shifting
3609 // it to the left) and restore the implicit mantissa bit,
3610 // i.e. convert the input to unsigned int64 shifted left by
3611 // kExponentBits.
3612 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3613 // Minus zero has the most significant bit set and the other
3614 // bits cleared.
3615 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3616 __ psllq(input_reg, HeapNumber::kExponentBits);
3617 __ por(input_reg, xmm_scratch);
3618
3619 // Get the amount to shift the input right in xmm_scratch.
3620 __ neg(result_reg);
3621 __ movd(xmm_scratch, Operand(result_reg));
3622
3623 // Shift the input right and extract low 32 bits.
3624 __ psrlq(input_reg, xmm_scratch);
3625 __ movd(Operand(result_reg), input_reg);
3626
3627 // Use the prepared mask in temp_reg to negate the result if necessary.
3628 __ xor_(result_reg, Operand(temp_reg));
3629 __ sub(result_reg, Operand(temp_reg));
3630 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003631 }
3632 } else {
3633 NearLabel done;
3634 __ cvttsd2si(result_reg, Operand(input_reg));
3635 __ cvtsi2sd(xmm0, Operand(result_reg));
3636 __ ucomisd(xmm0, input_reg);
3637 DeoptimizeIf(not_equal, instr->environment());
3638 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3639 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3640 // The integer converted back is equal to the original. We
3641 // only have to test if we got -0 as an input.
3642 __ test(result_reg, Operand(result_reg));
3643 __ j(not_zero, &done);
3644 __ movmskpd(result_reg, input_reg);
3645 // Bit 0 contains the sign of the double in input_reg.
3646 // If input was positive, we are ok and return 0, otherwise
3647 // deoptimize.
3648 __ and_(result_reg, 1);
3649 DeoptimizeIf(not_zero, instr->environment());
3650 }
3651 __ bind(&done);
3652 }
3653}
3654
3655
3656void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003657 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003658 __ test(ToRegister(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003659 DeoptimizeIf(not_zero, instr->environment());
3660}
3661
3662
3663void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
3664 LOperand* input = instr->InputAt(0);
3665 __ test(ToRegister(input), Immediate(kSmiTagMask));
3666 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003667}
3668
3669
3670void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003671 Register input = ToRegister(instr->InputAt(0));
3672 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003673 InstanceType first = instr->hydrogen()->first();
3674 InstanceType last = instr->hydrogen()->last();
3675
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003676 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003677
3678 // If there is only one type in the interval check for equality.
3679 if (first == last) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003680 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3681 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003682 DeoptimizeIf(not_equal, instr->environment());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003683 } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
3684 // String has a dedicated bit in instance type.
3685 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), kIsNotStringMask);
3686 DeoptimizeIf(not_zero, instr->environment());
3687 } else {
3688 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3689 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003690 DeoptimizeIf(below, instr->environment());
3691 // Omit check for the last type.
3692 if (last != LAST_TYPE) {
3693 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3694 static_cast<int8_t>(last));
3695 DeoptimizeIf(above, instr->environment());
3696 }
3697 }
3698}
3699
3700
3701void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003702 ASSERT(instr->InputAt(0)->IsRegister());
3703 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003704 __ cmp(reg, instr->hydrogen()->target());
3705 DeoptimizeIf(not_equal, instr->environment());
3706}
3707
3708
3709void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003710 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003711 ASSERT(input->IsRegister());
3712 Register reg = ToRegister(input);
3713 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3714 instr->hydrogen()->map());
3715 DeoptimizeIf(not_equal, instr->environment());
3716}
3717
3718
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003719void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 if (isolate()->heap()->InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003721 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722 isolate()->factory()->NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003723 __ mov(result, Operand::Cell(cell));
3724 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003725 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003726 }
3727}
3728
3729
3730void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003731 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003732
3733 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003734 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003735
3736 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003737 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003738
3739 // Check prototype maps up to the holder.
3740 while (!current_prototype.is_identical_to(holder)) {
3741 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3742 Handle<Map>(current_prototype->map()));
3743 DeoptimizeIf(not_equal, instr->environment());
3744 current_prototype =
3745 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3746 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003747 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003748 }
3749
3750 // Check the holder map.
3751 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3752 Handle<Map>(current_prototype->map()));
3753 DeoptimizeIf(not_equal, instr->environment());
3754}
3755
3756
3757void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
3758 // Setup the parameters to the stub/runtime call.
3759 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3760 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3761 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3762 __ push(Immediate(instr->hydrogen()->constant_elements()));
3763
3764 // Pick the right runtime function or stub to call.
3765 int length = instr->hydrogen()->length();
3766 if (instr->hydrogen()->IsCopyOnWrite()) {
3767 ASSERT(instr->hydrogen()->depth() == 1);
3768 FastCloneShallowArrayStub::Mode mode =
3769 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
3770 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003771 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003772 } else if (instr->hydrogen()->depth() > 1) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003773 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003774 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003775 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003776 } else {
3777 FastCloneShallowArrayStub::Mode mode =
3778 FastCloneShallowArrayStub::CLONE_ELEMENTS;
3779 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003780 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003781 }
3782}
3783
3784
3785void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003786 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003787 // Setup the parameters to the stub/runtime call.
3788 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3789 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3790 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3791 __ push(Immediate(instr->hydrogen()->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003792 int flags = instr->hydrogen()->fast_elements()
3793 ? ObjectLiteral::kFastElements
3794 : ObjectLiteral::kNoFlags;
3795 flags |= instr->hydrogen()->has_function()
3796 ? ObjectLiteral::kHasFunction
3797 : ObjectLiteral::kNoFlags;
3798 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003799
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003800 // Pick the right runtime function to call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003801 if (instr->hydrogen()->depth() > 1) {
3802 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
3803 } else {
3804 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
3805 }
3806}
3807
3808
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
3810 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
3811 __ push(eax);
3812 CallRuntime(Runtime::kToFastProperties, 1, instr);
3813}
3814
3815
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003816void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
3817 NearLabel materialized;
3818 // Registers will be used as follows:
3819 // edi = JS function.
3820 // ecx = literals array.
3821 // ebx = regexp literal.
3822 // eax = regexp literal clone.
3823 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3824 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
3825 int literal_offset = FixedArray::kHeaderSize +
3826 instr->hydrogen()->literal_index() * kPointerSize;
3827 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003828 __ cmp(ebx, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003829 __ j(not_equal, &materialized);
3830
3831 // Create regexp literal using runtime function
3832 // Result will be in eax.
3833 __ push(ecx);
3834 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3835 __ push(Immediate(instr->hydrogen()->pattern()));
3836 __ push(Immediate(instr->hydrogen()->flags()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003837 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003838 __ mov(ebx, eax);
3839
3840 __ bind(&materialized);
3841 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
3842 Label allocated, runtime_allocate;
3843 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
3844 __ jmp(&allocated);
3845
3846 __ bind(&runtime_allocate);
3847 __ push(ebx);
3848 __ push(Immediate(Smi::FromInt(size)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003849 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003850 __ pop(ebx);
3851
3852 __ bind(&allocated);
3853 // Copy the content into the newly allocated memory.
3854 // (Unroll copy loop once for better throughput).
3855 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
3856 __ mov(edx, FieldOperand(ebx, i));
3857 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
3858 __ mov(FieldOperand(eax, i), edx);
3859 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
3860 }
3861 if ((size % (2 * kPointerSize)) != 0) {
3862 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
3863 __ mov(FieldOperand(eax, size - kPointerSize), edx);
3864 }
3865}
3866
3867
3868void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
3869 // Use the fast case closure allocation code that allocates in new
3870 // space for nested functions that don't need literals cloning.
3871 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003872 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 if (!pretenure && shared_info->num_literals() == 0) {
3874 FastNewClosureStub stub(
3875 shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003876 __ push(Immediate(shared_info));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003877 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003878 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003879 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003880 __ push(Immediate(shared_info));
3881 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882 ? factory()->true_value()
3883 : factory()->false_value()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003884 CallRuntime(Runtime::kNewClosure, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003885 }
3886}
3887
3888
3889void LCodeGen::DoTypeof(LTypeof* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003890 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003891 if (input->IsConstantOperand()) {
3892 __ push(ToImmediate(input));
3893 } else {
3894 __ push(ToOperand(input));
3895 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003896 CallRuntime(Runtime::kTypeof, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003897}
3898
3899
3900void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003901 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003902 Register result = ToRegister(instr->result());
3903 Label true_label;
3904 Label false_label;
3905 NearLabel done;
3906
3907 Condition final_branch_condition = EmitTypeofIs(&true_label,
3908 &false_label,
3909 input,
3910 instr->type_literal());
3911 __ j(final_branch_condition, &true_label);
3912 __ bind(&false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003914 __ jmp(&done);
3915
3916 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003918
3919 __ bind(&done);
3920}
3921
3922
3923void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003924 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003925 int true_block = chunk_->LookupDestination(instr->true_block_id());
3926 int false_block = chunk_->LookupDestination(instr->false_block_id());
3927 Label* true_label = chunk_->GetAssemblyLabel(true_block);
3928 Label* false_label = chunk_->GetAssemblyLabel(false_block);
3929
3930 Condition final_branch_condition = EmitTypeofIs(true_label,
3931 false_label,
3932 input,
3933 instr->type_literal());
3934
3935 EmitBranch(true_block, false_block, final_branch_condition);
3936}
3937
3938
3939Condition LCodeGen::EmitTypeofIs(Label* true_label,
3940 Label* false_label,
3941 Register input,
3942 Handle<String> type_name) {
3943 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003945 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003946 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003947 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003948 final_branch_condition = equal;
3949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003950 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003951 __ JumpIfSmi(input, false_label);
3952 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
3953 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003954 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3955 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003956 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 } else if (type_name->Equals(heap()->boolean_symbol())) {
3959 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003960 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003961 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003962 final_branch_condition = equal;
3963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003964 } else if (type_name->Equals(heap()->undefined_symbol())) {
3965 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003966 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003968 // Check for undetectable objects => true.
3969 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
3970 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3971 1 << Map::kIsUndetectable);
3972 final_branch_condition = not_zero;
3973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003974 } else if (type_name->Equals(heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003975 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003976 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
3977 __ j(equal, true_label);
3978 // Regular expressions => 'function' (they are callable).
3979 __ CmpInstanceType(input, JS_REGEXP_TYPE);
3980 final_branch_condition = equal;
3981
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003983 __ JumpIfSmi(input, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 __ cmp(input, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003985 __ j(equal, true_label);
3986 // Regular expressions => 'function', not 'object'.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003987 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, input);
3988 __ j(below, false_label);
3989 __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
3990 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003991 // Check for undetectable objects => false.
3992 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3993 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003994 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995
3996 } else {
3997 final_branch_condition = not_equal;
3998 __ jmp(false_label);
3999 // A dead branch instruction will be generated after this point.
4000 }
4001
4002 return final_branch_condition;
4003}
4004
4005
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004006void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
4007 Register result = ToRegister(instr->result());
4008 NearLabel true_label;
4009 NearLabel false_label;
4010 NearLabel done;
4011
4012 EmitIsConstructCall(result);
4013 __ j(equal, &true_label);
4014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004015 __ mov(result, factory()->false_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004016 __ jmp(&done);
4017
4018 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 __ mov(result, factory()->true_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004020
4021 __ bind(&done);
4022}
4023
4024
4025void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4026 Register temp = ToRegister(instr->TempAt(0));
4027 int true_block = chunk_->LookupDestination(instr->true_block_id());
4028 int false_block = chunk_->LookupDestination(instr->false_block_id());
4029
4030 EmitIsConstructCall(temp);
4031 EmitBranch(true_block, false_block, equal);
4032}
4033
4034
4035void LCodeGen::EmitIsConstructCall(Register temp) {
4036 // Get the frame pointer for the calling frame.
4037 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4038
4039 // Skip the arguments adaptor frame if it exists.
4040 NearLabel check_frame_marker;
4041 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4042 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4043 __ j(not_equal, &check_frame_marker);
4044 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
4045
4046 // Check the marker in the calling frame.
4047 __ bind(&check_frame_marker);
4048 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4049 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
4050}
4051
4052
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004053void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
4054 // No code for lazy bailout instruction. Used to capture environment after a
4055 // call for populating the safepoint data with deoptimization data.
4056}
4057
4058
4059void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4060 DeoptimizeIf(no_condition, instr->environment());
4061}
4062
4063
4064void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
4065 LOperand* obj = instr->object();
4066 LOperand* key = instr->key();
4067 __ push(ToOperand(obj));
4068 if (key->IsConstantOperand()) {
4069 __ push(ToImmediate(key));
4070 } else {
4071 __ push(ToOperand(key));
4072 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004073 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4074 LPointerMap* pointers = instr->pointer_map();
4075 LEnvironment* env = instr->deoptimization_environment();
4076 RecordPosition(pointers->position());
4077 RegisterEnvironmentForDeoptimization(env);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004078 // Create safepoint generator that will also ensure enough space in the
4079 // reloc info for patching in deoptimization (since this is invoking a
4080 // builtin)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004081 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004082 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004083 env->deoptimization_index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004084 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004085 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004086 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
4087}
4088
4089
4090void LCodeGen::DoStackCheck(LStackCheck* instr) {
4091 // Perform stack overflow check.
4092 NearLabel done;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 ExternalReference stack_limit =
4094 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004095 __ cmp(esp, Operand::StaticVariable(stack_limit));
4096 __ j(above_equal, &done);
4097
4098 StackCheckStub stub;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004099 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004100 __ bind(&done);
4101}
4102
4103
4104void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
4105 // This is a pseudo-instruction that ensures that the environment here is
4106 // properly registered for deoptimization and records the assembler's PC
4107 // offset.
4108 LEnvironment* environment = instr->environment();
4109 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4110 instr->SpilledDoubleRegisterArray());
4111
4112 // If the environment were already registered, we would have no way of
4113 // backpatching it with the spill slot operands.
4114 ASSERT(!environment->HasBeenRegistered());
4115 RegisterEnvironmentForDeoptimization(environment);
4116 ASSERT(osr_pc_offset_ == -1);
4117 osr_pc_offset_ = masm()->pc_offset();
4118}
4119
4120
4121#undef __
4122
4123} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004124
4125#endif // V8_TARGET_ARCH_IA32