blob: d61ebdc0f6f62831ffccd267eeb9656397f77780 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
33#include "code-stubs.h"
34#include "stub-cache.h"
35
36namespace v8 {
37namespace internal {
38
39
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000040// When invoking builtins, we need to record the safepoint in the middle of
41// the invoke instruction sequence generated by the macro assembler.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042class SafepointGenerator : public PostCallGenerator {
43 public:
44 SafepointGenerator(LCodeGen* codegen,
45 LPointerMap* pointers,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000046 int deoptimization_index,
47 bool ensure_reloc_space = false)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048 : codegen_(codegen),
49 pointers_(pointers),
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000050 deoptimization_index_(deoptimization_index),
51 ensure_reloc_space_(ensure_reloc_space) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052 virtual ~SafepointGenerator() { }
53
54 virtual void Generate() {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000055 // Ensure that we have enough space in the reloc info to patch
56 // this with calls when doing deoptimization.
57 if (ensure_reloc_space_) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000058 codegen_->EnsureRelocSpaceForDeoptimization();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000059 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000060 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
61 }
62
63 private:
64 LCodeGen* codegen_;
65 LPointerMap* pointers_;
66 int deoptimization_index_;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000067 bool ensure_reloc_space_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000068};
69
70
71#define __ masm()->
72
73bool LCodeGen::GenerateCode() {
74 HPhase phase("Code generation", chunk());
75 ASSERT(is_unused());
76 status_ = GENERATING;
77 CpuFeatures::Scope scope(SSE2);
78 return GeneratePrologue() &&
79 GenerateBody() &&
80 GenerateDeferredCode() &&
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000081 GenerateRelocPadding() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000082 GenerateSafepointTable();
83}
84
85
86void LCodeGen::FinishCode(Handle<Code> code) {
87 ASSERT(is_done());
88 code->set_stack_slots(StackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000089 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000090 PopulateDeoptimizationData(code);
91}
92
93
94void LCodeGen::Abort(const char* format, ...) {
95 if (FLAG_trace_bailout) {
96 SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
97 PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
98 va_list arguments;
99 va_start(arguments, format);
100 OS::VPrint(format, arguments);
101 va_end(arguments);
102 PrintF("\n");
103 }
104 status_ = ABORTED;
105}
106
107
108void LCodeGen::Comment(const char* format, ...) {
109 if (!FLAG_code_comments) return;
110 char buffer[4 * KB];
111 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
112 va_list arguments;
113 va_start(arguments, format);
114 builder.AddFormattedList(format, arguments);
115 va_end(arguments);
116
117 // Copy the string before recording it in the assembler to avoid
118 // issues when the stack allocated buffer goes out of scope.
119 size_t length = builder.position();
120 Vector<char> copy = Vector<char>::New(length + 1);
121 memcpy(copy.start(), builder.Finalize(), copy.length());
122 masm()->RecordComment(copy.start());
123}
124
125
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000126bool LCodeGen::GenerateRelocPadding() {
127 int reloc_size = masm()->relocation_writer_size();
128 while (reloc_size < deoptimization_reloc_size.min_size) {
129 __ RecordComment(RelocInfo::kFillerCommentString, true);
130 reloc_size += RelocInfo::kRelocCommentSize;
131 }
132 return !is_aborted();
133}
134
135
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000136bool LCodeGen::GeneratePrologue() {
137 ASSERT(is_generating());
138
139#ifdef DEBUG
140 if (strlen(FLAG_stop_at) > 0 &&
141 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
142 __ int3();
143 }
144#endif
145
146 __ push(ebp); // Caller's frame pointer.
147 __ mov(ebp, esp);
148 __ push(esi); // Callee's context.
149 __ push(edi); // Callee's JS function.
150
151 // Reserve space for the stack slots needed by the code.
152 int slots = StackSlotCount();
153 if (slots > 0) {
154 if (FLAG_debug_code) {
155 __ mov(Operand(eax), Immediate(slots));
156 Label loop;
157 __ bind(&loop);
158 __ push(Immediate(kSlotsZapValue));
159 __ dec(eax);
160 __ j(not_zero, &loop);
161 } else {
162 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000163#ifdef _MSC_VER
164 // On windows, you may not access the stack more than one page below
165 // the most recently mapped page. To make the allocated area randomly
166 // accessible, we write to each page in turn (the value is irrelevant).
167 const int kPageSize = 4 * KB;
168 for (int offset = slots * kPointerSize - kPageSize;
169 offset > 0;
170 offset -= kPageSize) {
171 __ mov(Operand(esp, offset), eax);
172 }
173#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000174 }
175 }
176
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000177 // Possibly allocate a local context.
178 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
179 if (heap_slots > 0) {
180 Comment(";;; Allocate local context");
181 // Argument to NewContext is the function, which is still in edi.
182 __ push(edi);
183 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
184 FastNewContextStub stub(heap_slots);
185 __ CallStub(&stub);
186 } else {
187 __ CallRuntime(Runtime::kNewContext, 1);
188 }
189 RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
190 // Context is returned in both eax and esi. It replaces the context
191 // passed to us. It's saved in the stack and kept live in esi.
192 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
193
194 // Copy parameters into context if necessary.
195 int num_parameters = scope()->num_parameters();
196 for (int i = 0; i < num_parameters; i++) {
197 Slot* slot = scope()->parameter(i)->AsSlot();
198 if (slot != NULL && slot->type() == Slot::CONTEXT) {
199 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
200 (num_parameters - 1 - i) * kPointerSize;
201 // Load parameter from stack.
202 __ mov(eax, Operand(ebp, parameter_offset));
203 // Store it in the context.
204 int context_offset = Context::SlotOffset(slot->index());
205 __ mov(Operand(esi, context_offset), eax);
206 // Update the write barrier. This clobbers all involved
207 // registers, so we have to use a third register to avoid
208 // clobbering esi.
209 __ mov(ecx, esi);
210 __ RecordWrite(ecx, context_offset, eax, ebx);
211 }
212 }
213 Comment(";;; End allocate local context");
214 }
215
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000216 // Trace the call.
217 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000218 // We have not executed any compiled code yet, so esi still holds the
219 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000220 __ CallRuntime(Runtime::kTraceEnter, 0);
221 }
222 return !is_aborted();
223}
224
225
226bool LCodeGen::GenerateBody() {
227 ASSERT(is_generating());
228 bool emit_instructions = true;
229 for (current_instruction_ = 0;
230 !is_aborted() && current_instruction_ < instructions_->length();
231 current_instruction_++) {
232 LInstruction* instr = instructions_->at(current_instruction_);
233 if (instr->IsLabel()) {
234 LLabel* label = LLabel::cast(instr);
235 emit_instructions = !label->HasReplacement();
236 }
237
238 if (emit_instructions) {
239 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
240 instr->CompileToNative(this);
241 }
242 }
243 return !is_aborted();
244}
245
246
247LInstruction* LCodeGen::GetNextInstruction() {
248 if (current_instruction_ < instructions_->length() - 1) {
249 return instructions_->at(current_instruction_ + 1);
250 } else {
251 return NULL;
252 }
253}
254
255
256bool LCodeGen::GenerateDeferredCode() {
257 ASSERT(is_generating());
258 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
259 LDeferredCode* code = deferred_[i];
260 __ bind(code->entry());
261 code->Generate();
262 __ jmp(code->exit());
263 }
264
265 // Deferred code is the last part of the instruction sequence. Mark
266 // the generated code as done unless we bailed out.
267 if (!is_aborted()) status_ = DONE;
268 return !is_aborted();
269}
270
271
272bool LCodeGen::GenerateSafepointTable() {
273 ASSERT(is_done());
274 safepoints_.Emit(masm(), StackSlotCount());
275 return !is_aborted();
276}
277
278
279Register LCodeGen::ToRegister(int index) const {
280 return Register::FromAllocationIndex(index);
281}
282
283
284XMMRegister LCodeGen::ToDoubleRegister(int index) const {
285 return XMMRegister::FromAllocationIndex(index);
286}
287
288
289Register LCodeGen::ToRegister(LOperand* op) const {
290 ASSERT(op->IsRegister());
291 return ToRegister(op->index());
292}
293
294
295XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
296 ASSERT(op->IsDoubleRegister());
297 return ToDoubleRegister(op->index());
298}
299
300
301int LCodeGen::ToInteger32(LConstantOperand* op) const {
302 Handle<Object> value = chunk_->LookupLiteral(op);
303 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
304 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
305 value->Number());
306 return static_cast<int32_t>(value->Number());
307}
308
309
310Immediate LCodeGen::ToImmediate(LOperand* op) {
311 LConstantOperand* const_op = LConstantOperand::cast(op);
312 Handle<Object> literal = chunk_->LookupLiteral(const_op);
313 Representation r = chunk_->LookupLiteralRepresentation(const_op);
314 if (r.IsInteger32()) {
315 ASSERT(literal->IsNumber());
316 return Immediate(static_cast<int32_t>(literal->Number()));
317 } else if (r.IsDouble()) {
318 Abort("unsupported double immediate");
319 }
320 ASSERT(r.IsTagged());
321 return Immediate(literal);
322}
323
324
325Operand LCodeGen::ToOperand(LOperand* op) const {
326 if (op->IsRegister()) return Operand(ToRegister(op));
327 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
328 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
329 int index = op->index();
330 if (index >= 0) {
331 // Local or spill slot. Skip the frame pointer, function, and
332 // context in the fixed part of the frame.
333 return Operand(ebp, -(index + 3) * kPointerSize);
334 } else {
335 // Incoming parameter. Skip the return address.
336 return Operand(ebp, -(index - 1) * kPointerSize);
337 }
338}
339
340
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000341Operand LCodeGen::HighOperand(LOperand* op) {
342 ASSERT(op->IsDoubleStackSlot());
343 int index = op->index();
344 int offset = (index >= 0) ? index + 3 : index - 1;
345 return Operand(ebp, -offset * kPointerSize);
346}
347
348
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000349void LCodeGen::WriteTranslation(LEnvironment* environment,
350 Translation* translation) {
351 if (environment == NULL) return;
352
353 // The translation includes one command per value in the environment.
354 int translation_size = environment->values()->length();
355 // The output frame height does not include the parameters.
356 int height = translation_size - environment->parameter_count();
357
358 WriteTranslation(environment->outer(), translation);
359 int closure_id = DefineDeoptimizationLiteral(environment->closure());
360 translation->BeginFrame(environment->ast_id(), closure_id, height);
361 for (int i = 0; i < translation_size; ++i) {
362 LOperand* value = environment->values()->at(i);
363 // spilled_registers_ and spilled_double_registers_ are either
364 // both NULL or both set.
365 if (environment->spilled_registers() != NULL && value != NULL) {
366 if (value->IsRegister() &&
367 environment->spilled_registers()[value->index()] != NULL) {
368 translation->MarkDuplicate();
369 AddToTranslation(translation,
370 environment->spilled_registers()[value->index()],
371 environment->HasTaggedValueAt(i));
372 } else if (
373 value->IsDoubleRegister() &&
374 environment->spilled_double_registers()[value->index()] != NULL) {
375 translation->MarkDuplicate();
376 AddToTranslation(
377 translation,
378 environment->spilled_double_registers()[value->index()],
379 false);
380 }
381 }
382
383 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
384 }
385}
386
387
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000388void LCodeGen::EnsureRelocSpaceForDeoptimization() {
389 // Since we patch the reloc info with RUNTIME_ENTRY calls every patch
390 // site will take up 2 bytes + any pc-jumps.
391 // We are conservative and always reserver 6 bytes in case where a
392 // simple pc-jump is not enough.
393 uint32_t pc_delta =
394 masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset;
395 if (is_uintn(pc_delta, 6)) {
396 deoptimization_reloc_size.min_size += 2;
397 } else {
398 deoptimization_reloc_size.min_size += 6;
399 }
400 deoptimization_reloc_size.last_pc_offset = masm()->pc_offset();
401}
402
403
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000404void LCodeGen::AddToTranslation(Translation* translation,
405 LOperand* op,
406 bool is_tagged) {
407 if (op == NULL) {
408 // TODO(twuerthinger): Introduce marker operands to indicate that this value
409 // is not present and must be reconstructed from the deoptimizer. Currently
410 // this is only used for the arguments object.
411 translation->StoreArgumentsObject();
412 } else if (op->IsStackSlot()) {
413 if (is_tagged) {
414 translation->StoreStackSlot(op->index());
415 } else {
416 translation->StoreInt32StackSlot(op->index());
417 }
418 } else if (op->IsDoubleStackSlot()) {
419 translation->StoreDoubleStackSlot(op->index());
420 } else if (op->IsArgument()) {
421 ASSERT(is_tagged);
422 int src_index = StackSlotCount() + op->index();
423 translation->StoreStackSlot(src_index);
424 } else if (op->IsRegister()) {
425 Register reg = ToRegister(op);
426 if (is_tagged) {
427 translation->StoreRegister(reg);
428 } else {
429 translation->StoreInt32Register(reg);
430 }
431 } else if (op->IsDoubleRegister()) {
432 XMMRegister reg = ToDoubleRegister(op);
433 translation->StoreDoubleRegister(reg);
434 } else if (op->IsConstantOperand()) {
435 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
436 int src_index = DefineDeoptimizationLiteral(literal);
437 translation->StoreLiteral(src_index);
438 } else {
439 UNREACHABLE();
440 }
441}
442
443
444void LCodeGen::CallCode(Handle<Code> code,
445 RelocInfo::Mode mode,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000446 LInstruction* instr,
447 bool adjusted) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000448 ASSERT(instr != NULL);
449 LPointerMap* pointers = instr->pointer_map();
450 RecordPosition(pointers->position());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000452 if (!adjusted) {
453 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
454 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000455 __ call(code, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000456
457 EnsureRelocSpaceForDeoptimization();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000458 RegisterLazyDeoptimization(instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000459
460 // Signal that we don't inline smi code before these stubs in the
461 // optimizing code generator.
462 if (code->kind() == Code::TYPE_RECORDING_BINARY_OP_IC ||
463 code->kind() == Code::COMPARE_IC) {
464 __ nop();
465 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000466}
467
468
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000469void LCodeGen::CallRuntime(Runtime::Function* fun,
470 int argc,
471 LInstruction* instr,
472 bool adjusted) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000473 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000474 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000475 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000476 RecordPosition(pointers->position());
477
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000478 if (!adjusted) {
479 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
480 }
481 __ CallRuntime(fun, argc);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000482 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000483}
484
485
486void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr) {
487 // Create the environment to bailout to. If the call has side effects
488 // execution has to continue after the call otherwise execution can continue
489 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000490 LEnvironment* deoptimization_environment;
491 if (instr->HasDeoptimizationEnvironment()) {
492 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000493 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000494 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000495 }
496
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000497 RegisterEnvironmentForDeoptimization(deoptimization_environment);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000498 RecordSafepoint(instr->pointer_map(),
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000499 deoptimization_environment->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000500}
501
502
503void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
504 if (!environment->HasBeenRegistered()) {
505 // Physical stack frame layout:
506 // -x ............. -4 0 ..................................... y
507 // [incoming arguments] [spill slots] [pushed outgoing arguments]
508
509 // Layout of the environment:
510 // 0 ..................................................... size-1
511 // [parameters] [locals] [expression stack including arguments]
512
513 // Layout of the translation:
514 // 0 ........................................................ size - 1 + 4
515 // [expression stack including arguments] [locals] [4 words] [parameters]
516 // |>------------ translation_size ------------<|
517
518 int frame_count = 0;
519 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
520 ++frame_count;
521 }
522 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000523 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000524 int deoptimization_index = deoptimizations_.length();
525 environment->Register(deoptimization_index, translation.index());
526 deoptimizations_.Add(environment);
527 }
528}
529
530
531void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
532 RegisterEnvironmentForDeoptimization(environment);
533 ASSERT(environment->HasBeenRegistered());
534 int id = environment->deoptimization_index();
535 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
536 ASSERT(entry != NULL);
537 if (entry == NULL) {
538 Abort("bailout was not prepared");
539 return;
540 }
541
542 if (FLAG_deopt_every_n_times != 0) {
543 Handle<SharedFunctionInfo> shared(info_->shared_info());
544 Label no_deopt;
545 __ pushfd();
546 __ push(eax);
547 __ push(ebx);
548 __ mov(ebx, shared);
549 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
550 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
551 __ j(not_zero, &no_deopt);
552 if (FLAG_trap_on_deopt) __ int3();
553 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
554 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
555 __ pop(ebx);
556 __ pop(eax);
557 __ popfd();
558 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
559
560 __ bind(&no_deopt);
561 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
562 __ pop(ebx);
563 __ pop(eax);
564 __ popfd();
565 }
566
567 if (cc == no_condition) {
568 if (FLAG_trap_on_deopt) __ int3();
569 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
570 } else {
571 if (FLAG_trap_on_deopt) {
572 NearLabel done;
573 __ j(NegateCondition(cc), &done);
574 __ int3();
575 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
576 __ bind(&done);
577 } else {
578 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY, not_taken);
579 }
580 }
581}
582
583
584void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
585 int length = deoptimizations_.length();
586 if (length == 0) return;
587 ASSERT(FLAG_deopt);
588 Handle<DeoptimizationInputData> data =
589 Factory::NewDeoptimizationInputData(length, TENURED);
590
591 data->SetTranslationByteArray(*translations_.CreateByteArray());
592 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
593
594 Handle<FixedArray> literals =
595 Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
596 for (int i = 0; i < deoptimization_literals_.length(); i++) {
597 literals->set(i, *deoptimization_literals_[i]);
598 }
599 data->SetLiteralArray(*literals);
600
601 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
602 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
603
604 // Populate the deoptimization entries.
605 for (int i = 0; i < length; i++) {
606 LEnvironment* env = deoptimizations_[i];
607 data->SetAstId(i, Smi::FromInt(env->ast_id()));
608 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
609 data->SetArgumentsStackHeight(i,
610 Smi::FromInt(env->arguments_stack_height()));
611 }
612 code->set_deoptimization_data(*data);
613}
614
615
616int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
617 int result = deoptimization_literals_.length();
618 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
619 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
620 }
621 deoptimization_literals_.Add(literal);
622 return result;
623}
624
625
626void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
627 ASSERT(deoptimization_literals_.length() == 0);
628
629 const ZoneList<Handle<JSFunction> >* inlined_closures =
630 chunk()->inlined_closures();
631
632 for (int i = 0, length = inlined_closures->length();
633 i < length;
634 i++) {
635 DefineDeoptimizationLiteral(inlined_closures->at(i));
636 }
637
638 inlined_function_count_ = deoptimization_literals_.length();
639}
640
641
ager@chromium.org378b34e2011-01-28 08:04:38 +0000642void LCodeGen::RecordSafepoint(
643 LPointerMap* pointers,
644 Safepoint::Kind kind,
645 int arguments,
646 int deoptimization_index) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000647 const ZoneList<LOperand*>* operands = pointers->operands();
648 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000649 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000650 for (int i = 0; i < operands->length(); i++) {
651 LOperand* pointer = operands->at(i);
652 if (pointer->IsStackSlot()) {
653 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000654 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
655 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000656 }
657 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000658}
659
660
661void LCodeGen::RecordSafepoint(LPointerMap* pointers,
662 int deoptimization_index) {
663 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664}
665
666
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000667void LCodeGen::RecordSafepoint(int deoptimization_index) {
668 LPointerMap empty_pointers(RelocInfo::kNoPosition);
669 RecordSafepoint(&empty_pointers, deoptimization_index);
670}
671
672
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000673void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
674 int arguments,
675 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000676 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
677 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678}
679
680
681void LCodeGen::RecordPosition(int position) {
682 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
683 masm()->positions_recorder()->RecordPosition(position);
684}
685
686
687void LCodeGen::DoLabel(LLabel* label) {
688 if (label->is_loop_header()) {
689 Comment(";;; B%d - LOOP entry", label->block_id());
690 } else {
691 Comment(";;; B%d", label->block_id());
692 }
693 __ bind(label->label());
694 current_block_ = label->block_id();
695 LCodeGen::DoGap(label);
696}
697
698
699void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000700 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701}
702
703
704void LCodeGen::DoGap(LGap* gap) {
705 for (int i = LGap::FIRST_INNER_POSITION;
706 i <= LGap::LAST_INNER_POSITION;
707 i++) {
708 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
709 LParallelMove* move = gap->GetParallelMove(inner_pos);
710 if (move != NULL) DoParallelMove(move);
711 }
712
713 LInstruction* next = GetNextInstruction();
714 if (next != NULL && next->IsLazyBailout()) {
715 int pc = masm()->pc_offset();
716 safepoints_.SetPcAfterGap(pc);
717 }
718}
719
720
721void LCodeGen::DoParameter(LParameter* instr) {
722 // Nothing to do.
723}
724
725
726void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000727 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000728 ASSERT(ToRegister(instr->result()).is(eax));
729 switch (instr->hydrogen()->major_key()) {
730 case CodeStub::RegExpConstructResult: {
731 RegExpConstructResultStub stub;
732 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
733 break;
734 }
735 case CodeStub::RegExpExec: {
736 RegExpExecStub stub;
737 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
738 break;
739 }
740 case CodeStub::SubString: {
741 SubStringStub stub;
742 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
743 break;
744 }
745 case CodeStub::StringCharAt: {
746 StringCharAtStub stub;
747 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
748 break;
749 }
750 case CodeStub::MathPow: {
751 MathPowStub stub;
752 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
753 break;
754 }
755 case CodeStub::NumberToString: {
756 NumberToStringStub stub;
757 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
758 break;
759 }
760 case CodeStub::StringAdd: {
761 StringAddStub stub(NO_STRING_ADD_FLAGS);
762 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
763 break;
764 }
765 case CodeStub::StringCompare: {
766 StringCompareStub stub;
767 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
768 break;
769 }
770 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000771 TranscendentalCacheStub stub(instr->transcendental_type(),
772 TranscendentalCacheStub::TAGGED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000773 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
774 break;
775 }
776 default:
777 UNREACHABLE();
778 }
779}
780
781
782void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
783 // Nothing to do.
784}
785
786
787void LCodeGen::DoModI(LModI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000788 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789 ASSERT(ToRegister(instr->result()).is(edx));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000790 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
791 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
792 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793
794 Register right_reg = ToRegister(right);
795
796 // Check for x % 0.
797 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
798 __ test(right_reg, ToOperand(right));
799 DeoptimizeIf(zero, instr->environment());
800 }
801
802 // Sign extend to edx.
803 __ cdq();
804
805 // Check for (0 % -x) that will produce negative zero.
806 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
807 NearLabel positive_left;
808 NearLabel done;
809 __ test(eax, Operand(eax));
810 __ j(not_sign, &positive_left);
811 __ idiv(right_reg);
812
813 // Test the remainder for 0, because then the result would be -0.
814 __ test(edx, Operand(edx));
815 __ j(not_zero, &done);
816
817 DeoptimizeIf(no_condition, instr->environment());
818 __ bind(&positive_left);
819 __ idiv(right_reg);
820 __ bind(&done);
821 } else {
822 __ idiv(right_reg);
823 }
824}
825
826
827void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000828 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000830 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
831 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
832 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000833
834 Register left_reg = eax;
835
836 // Check for x / 0.
837 Register right_reg = ToRegister(right);
838 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
839 __ test(right_reg, ToOperand(right));
840 DeoptimizeIf(zero, instr->environment());
841 }
842
843 // Check for (0 / -x) that will produce negative zero.
844 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
845 NearLabel left_not_zero;
846 __ test(left_reg, Operand(left_reg));
847 __ j(not_zero, &left_not_zero);
848 __ test(right_reg, ToOperand(right));
849 DeoptimizeIf(sign, instr->environment());
850 __ bind(&left_not_zero);
851 }
852
853 // Check for (-kMinInt / -1).
854 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
855 NearLabel left_not_min_int;
856 __ cmp(left_reg, kMinInt);
857 __ j(not_zero, &left_not_min_int);
858 __ cmp(right_reg, -1);
859 DeoptimizeIf(zero, instr->environment());
860 __ bind(&left_not_min_int);
861 }
862
863 // Sign extend to edx.
864 __ cdq();
865 __ idiv(right_reg);
866
867 // Deoptimize if remainder is not 0.
868 __ test(edx, Operand(edx));
869 DeoptimizeIf(not_zero, instr->environment());
870}
871
872
873void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000874 Register left = ToRegister(instr->InputAt(0));
875 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000876
877 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000878 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000879 }
880
881 if (right->IsConstantOperand()) {
882 __ imul(left, left, ToInteger32(LConstantOperand::cast(right)));
883 } else {
884 __ imul(left, ToOperand(right));
885 }
886
887 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
888 DeoptimizeIf(overflow, instr->environment());
889 }
890
891 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
892 // Bail out if the result is supposed to be negative zero.
893 NearLabel done;
894 __ test(left, Operand(left));
895 __ j(not_zero, &done);
896 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000897 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000898 DeoptimizeIf(no_condition, instr->environment());
899 }
900 } else {
901 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000902 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000903 DeoptimizeIf(sign, instr->environment());
904 }
905 __ bind(&done);
906 }
907}
908
909
910void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000911 LOperand* left = instr->InputAt(0);
912 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000913 ASSERT(left->Equals(instr->result()));
914 ASSERT(left->IsRegister());
915
916 if (right->IsConstantOperand()) {
917 int right_operand = ToInteger32(LConstantOperand::cast(right));
918 switch (instr->op()) {
919 case Token::BIT_AND:
920 __ and_(ToRegister(left), right_operand);
921 break;
922 case Token::BIT_OR:
923 __ or_(ToRegister(left), right_operand);
924 break;
925 case Token::BIT_XOR:
926 __ xor_(ToRegister(left), right_operand);
927 break;
928 default:
929 UNREACHABLE();
930 break;
931 }
932 } else {
933 switch (instr->op()) {
934 case Token::BIT_AND:
935 __ and_(ToRegister(left), ToOperand(right));
936 break;
937 case Token::BIT_OR:
938 __ or_(ToRegister(left), ToOperand(right));
939 break;
940 case Token::BIT_XOR:
941 __ xor_(ToRegister(left), ToOperand(right));
942 break;
943 default:
944 UNREACHABLE();
945 break;
946 }
947 }
948}
949
950
951void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000952 LOperand* left = instr->InputAt(0);
953 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000954 ASSERT(left->Equals(instr->result()));
955 ASSERT(left->IsRegister());
956 if (right->IsRegister()) {
957 ASSERT(ToRegister(right).is(ecx));
958
959 switch (instr->op()) {
960 case Token::SAR:
961 __ sar_cl(ToRegister(left));
962 break;
963 case Token::SHR:
964 __ shr_cl(ToRegister(left));
965 if (instr->can_deopt()) {
966 __ test(ToRegister(left), Immediate(0x80000000));
967 DeoptimizeIf(not_zero, instr->environment());
968 }
969 break;
970 case Token::SHL:
971 __ shl_cl(ToRegister(left));
972 break;
973 default:
974 UNREACHABLE();
975 break;
976 }
977 } else {
978 int value = ToInteger32(LConstantOperand::cast(right));
979 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
980 switch (instr->op()) {
981 case Token::SAR:
982 if (shift_count != 0) {
983 __ sar(ToRegister(left), shift_count);
984 }
985 break;
986 case Token::SHR:
987 if (shift_count == 0 && instr->can_deopt()) {
988 __ test(ToRegister(left), Immediate(0x80000000));
989 DeoptimizeIf(not_zero, instr->environment());
990 } else {
991 __ shr(ToRegister(left), shift_count);
992 }
993 break;
994 case Token::SHL:
995 if (shift_count != 0) {
996 __ shl(ToRegister(left), shift_count);
997 }
998 break;
999 default:
1000 UNREACHABLE();
1001 break;
1002 }
1003 }
1004}
1005
1006
1007void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001008 LOperand* left = instr->InputAt(0);
1009 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001010 ASSERT(left->Equals(instr->result()));
1011
1012 if (right->IsConstantOperand()) {
1013 __ sub(ToOperand(left), ToImmediate(right));
1014 } else {
1015 __ sub(ToRegister(left), ToOperand(right));
1016 }
1017 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1018 DeoptimizeIf(overflow, instr->environment());
1019 }
1020}
1021
1022
1023void LCodeGen::DoConstantI(LConstantI* instr) {
1024 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001025 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001026}
1027
1028
1029void LCodeGen::DoConstantD(LConstantD* instr) {
1030 ASSERT(instr->result()->IsDoubleRegister());
1031 XMMRegister res = ToDoubleRegister(instr->result());
1032 double v = instr->value();
1033 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1034 // do so if the constant is -0.0.
1035 if (BitCast<uint64_t, double>(v) == 0) {
1036 __ xorpd(res, res);
1037 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001038 Register temp = ToRegister(instr->TempAt(0));
1039 uint64_t int_val = BitCast<uint64_t, double>(v);
1040 int32_t lower = static_cast<int32_t>(int_val);
1041 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
1042 if (CpuFeatures::IsSupported(SSE4_1)) {
1043 CpuFeatures::Scope scope(SSE4_1);
1044 if (lower != 0) {
1045 __ Set(temp, Immediate(lower));
1046 __ movd(res, Operand(temp));
1047 __ Set(temp, Immediate(upper));
1048 __ pinsrd(res, Operand(temp), 1);
1049 } else {
1050 __ xorpd(res, res);
1051 __ Set(temp, Immediate(upper));
1052 __ pinsrd(res, Operand(temp), 1);
1053 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001054 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001055 __ Set(temp, Immediate(upper));
1056 __ movd(res, Operand(temp));
1057 __ psllq(res, 32);
1058 if (lower != 0) {
1059 __ Set(temp, Immediate(lower));
1060 __ movd(xmm0, Operand(temp));
1061 __ por(res, xmm0);
1062 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001063 }
1064 }
1065}
1066
1067
1068void LCodeGen::DoConstantT(LConstantT* instr) {
1069 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001070 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001071}
1072
1073
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001074void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001076 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001077 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1078}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001079
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001080
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001081void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
1082 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001083 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001084 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001085}
1086
1087
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001088void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
1089 Register result = ToRegister(instr->result());
1090 Register array = ToRegister(instr->InputAt(0));
1091 __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
1092}
1093
1094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001095void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001096 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001097 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001098 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099 ASSERT(input.is(result));
1100 NearLabel done;
1101 // If the object is a smi return the object.
1102 __ test(input, Immediate(kSmiTagMask));
1103 __ j(zero, &done);
1104
1105 // If the object is not a value type, return the object.
1106 __ CmpObjectType(input, JS_VALUE_TYPE, map);
1107 __ j(not_equal, &done);
1108 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1109
1110 __ bind(&done);
1111}
1112
1113
1114void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001115 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001116 ASSERT(input->Equals(instr->result()));
1117 __ not_(ToRegister(input));
1118}
1119
1120
1121void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001122 __ push(ToOperand(instr->InputAt(0)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001123 CallRuntime(Runtime::kThrow, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001124
1125 if (FLAG_debug_code) {
1126 Comment("Unreachable code.");
1127 __ int3();
1128 }
1129}
1130
1131
1132void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001133 LOperand* left = instr->InputAt(0);
1134 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001135 ASSERT(left->Equals(instr->result()));
1136
1137 if (right->IsConstantOperand()) {
1138 __ add(ToOperand(left), ToImmediate(right));
1139 } else {
1140 __ add(ToRegister(left), ToOperand(right));
1141 }
1142
1143 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1144 DeoptimizeIf(overflow, instr->environment());
1145 }
1146}
1147
1148
1149void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001150 LOperand* left = instr->InputAt(0);
1151 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001152 // Modulo uses a fixed result register.
1153 ASSERT(instr->op() == Token::MOD || left->Equals(instr->result()));
1154 switch (instr->op()) {
1155 case Token::ADD:
1156 __ addsd(ToDoubleRegister(left), ToDoubleRegister(right));
1157 break;
1158 case Token::SUB:
1159 __ subsd(ToDoubleRegister(left), ToDoubleRegister(right));
1160 break;
1161 case Token::MUL:
1162 __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right));
1163 break;
1164 case Token::DIV:
1165 __ divsd(ToDoubleRegister(left), ToDoubleRegister(right));
1166 break;
1167 case Token::MOD: {
1168 // Pass two doubles as arguments on the stack.
1169 __ PrepareCallCFunction(4, eax);
1170 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
1171 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
1172 __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
1173
1174 // Return value is in st(0) on ia32.
1175 // Store it into the (fixed) result register.
1176 __ sub(Operand(esp), Immediate(kDoubleSize));
1177 __ fstp_d(Operand(esp, 0));
1178 __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
1179 __ add(Operand(esp), Immediate(kDoubleSize));
1180 break;
1181 }
1182 default:
1183 UNREACHABLE();
1184 break;
1185 }
1186}
1187
1188
1189void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001190 ASSERT(ToRegister(instr->InputAt(0)).is(edx));
1191 ASSERT(ToRegister(instr->InputAt(1)).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001192 ASSERT(ToRegister(instr->result()).is(eax));
1193
1194 TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001195 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001196}
1197
1198
1199int LCodeGen::GetNextEmittedBlock(int block) {
1200 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1201 LLabel* label = chunk_->GetLabel(i);
1202 if (!label->HasReplacement()) return i;
1203 }
1204 return -1;
1205}
1206
1207
1208void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1209 int next_block = GetNextEmittedBlock(current_block_);
1210 right_block = chunk_->LookupDestination(right_block);
1211 left_block = chunk_->LookupDestination(left_block);
1212
1213 if (right_block == left_block) {
1214 EmitGoto(left_block);
1215 } else if (left_block == next_block) {
1216 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1217 } else if (right_block == next_block) {
1218 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1219 } else {
1220 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1221 __ jmp(chunk_->GetAssemblyLabel(right_block));
1222 }
1223}
1224
1225
1226void LCodeGen::DoBranch(LBranch* instr) {
1227 int true_block = chunk_->LookupDestination(instr->true_block_id());
1228 int false_block = chunk_->LookupDestination(instr->false_block_id());
1229
1230 Representation r = instr->hydrogen()->representation();
1231 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001232 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001233 __ test(reg, Operand(reg));
1234 EmitBranch(true_block, false_block, not_zero);
1235 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001236 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001237 __ xorpd(xmm0, xmm0);
1238 __ ucomisd(reg, xmm0);
1239 EmitBranch(true_block, false_block, not_equal);
1240 } else {
1241 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001242 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001243 if (instr->hydrogen()->type().IsBoolean()) {
1244 __ cmp(reg, Factory::true_value());
1245 EmitBranch(true_block, false_block, equal);
1246 } else {
1247 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1248 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1249
1250 __ cmp(reg, Factory::undefined_value());
1251 __ j(equal, false_label);
1252 __ cmp(reg, Factory::true_value());
1253 __ j(equal, true_label);
1254 __ cmp(reg, Factory::false_value());
1255 __ j(equal, false_label);
1256 __ test(reg, Operand(reg));
1257 __ j(equal, false_label);
1258 __ test(reg, Immediate(kSmiTagMask));
1259 __ j(zero, true_label);
1260
1261 // Test for double values. Zero is false.
1262 NearLabel call_stub;
1263 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1264 Factory::heap_number_map());
1265 __ j(not_equal, &call_stub);
1266 __ fldz();
1267 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1268 __ FCmp();
1269 __ j(zero, false_label);
1270 __ jmp(true_label);
1271
1272 // The conversion stub doesn't cause garbage collections so it's
1273 // safe to not record a safepoint after the call.
1274 __ bind(&call_stub);
1275 ToBooleanStub stub;
1276 __ pushad();
1277 __ push(reg);
1278 __ CallStub(&stub);
1279 __ test(eax, Operand(eax));
1280 __ popad();
1281 EmitBranch(true_block, false_block, not_zero);
1282 }
1283 }
1284}
1285
1286
1287void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
1288 block = chunk_->LookupDestination(block);
1289 int next_block = GetNextEmittedBlock(current_block_);
1290 if (block != next_block) {
1291 // Perform stack overflow check if this goto needs it before jumping.
1292 if (deferred_stack_check != NULL) {
1293 ExternalReference stack_limit =
1294 ExternalReference::address_of_stack_limit();
1295 __ cmp(esp, Operand::StaticVariable(stack_limit));
1296 __ j(above_equal, chunk_->GetAssemblyLabel(block));
1297 __ jmp(deferred_stack_check->entry());
1298 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1299 } else {
1300 __ jmp(chunk_->GetAssemblyLabel(block));
1301 }
1302 }
1303}
1304
1305
1306void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
1307 __ pushad();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001308 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
1310 RecordSafepointWithRegisters(
1311 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1312 __ popad();
1313}
1314
1315void LCodeGen::DoGoto(LGoto* instr) {
1316 class DeferredStackCheck: public LDeferredCode {
1317 public:
1318 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1319 : LDeferredCode(codegen), instr_(instr) { }
1320 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1321 private:
1322 LGoto* instr_;
1323 };
1324
1325 DeferredStackCheck* deferred = NULL;
1326 if (instr->include_stack_check()) {
1327 deferred = new DeferredStackCheck(this, instr);
1328 }
1329 EmitGoto(instr->block_id(), deferred);
1330}
1331
1332
1333Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1334 Condition cond = no_condition;
1335 switch (op) {
1336 case Token::EQ:
1337 case Token::EQ_STRICT:
1338 cond = equal;
1339 break;
1340 case Token::LT:
1341 cond = is_unsigned ? below : less;
1342 break;
1343 case Token::GT:
1344 cond = is_unsigned ? above : greater;
1345 break;
1346 case Token::LTE:
1347 cond = is_unsigned ? below_equal : less_equal;
1348 break;
1349 case Token::GTE:
1350 cond = is_unsigned ? above_equal : greater_equal;
1351 break;
1352 case Token::IN:
1353 case Token::INSTANCEOF:
1354 default:
1355 UNREACHABLE();
1356 }
1357 return cond;
1358}
1359
1360
1361void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
1362 if (right->IsConstantOperand()) {
1363 __ cmp(ToOperand(left), ToImmediate(right));
1364 } else {
1365 __ cmp(ToRegister(left), ToOperand(right));
1366 }
1367}
1368
1369
1370void LCodeGen::DoCmpID(LCmpID* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001371 LOperand* left = instr->InputAt(0);
1372 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001373 LOperand* result = instr->result();
1374
1375 NearLabel unordered;
1376 if (instr->is_double()) {
1377 // Don't base result on EFLAGS when a NaN is involved. Instead
1378 // jump to the unordered case, which produces a false value.
1379 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1380 __ j(parity_even, &unordered, not_taken);
1381 } else {
1382 EmitCmpI(left, right);
1383 }
1384
1385 NearLabel done;
1386 Condition cc = TokenToCondition(instr->op(), instr->is_double());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001387 __ mov(ToRegister(result), Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388 __ j(cc, &done);
1389
1390 __ bind(&unordered);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001391 __ mov(ToRegister(result), Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001392 __ bind(&done);
1393}
1394
1395
1396void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* 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 int false_block = chunk_->LookupDestination(instr->false_block_id());
1400 int true_block = chunk_->LookupDestination(instr->true_block_id());
1401
1402 if (instr->is_double()) {
1403 // Don't base result on EFLAGS when a NaN is involved. Instead
1404 // jump to the false block.
1405 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1406 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1407 } else {
1408 EmitCmpI(left, right);
1409 }
1410
1411 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1412 EmitBranch(true_block, false_block, cc);
1413}
1414
1415
1416void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001417 Register left = ToRegister(instr->InputAt(0));
1418 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 Register result = ToRegister(instr->result());
1420
1421 __ cmp(left, Operand(right));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001422 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001423 NearLabel done;
1424 __ j(equal, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001425 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426 __ bind(&done);
1427}
1428
1429
1430void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001431 Register left = ToRegister(instr->InputAt(0));
1432 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001433 int false_block = chunk_->LookupDestination(instr->false_block_id());
1434 int true_block = chunk_->LookupDestination(instr->true_block_id());
1435
1436 __ cmp(left, Operand(right));
1437 EmitBranch(true_block, false_block, equal);
1438}
1439
1440
1441void LCodeGen::DoIsNull(LIsNull* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001442 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001443 Register result = ToRegister(instr->result());
1444
1445 // TODO(fsc): If the expression is known to be a smi, then it's
1446 // definitely not null. Materialize false.
1447
1448 __ cmp(reg, Factory::null_value());
1449 if (instr->is_strict()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001450 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001451 NearLabel done;
1452 __ j(equal, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001453 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001454 __ bind(&done);
1455 } else {
1456 NearLabel true_value, false_value, done;
1457 __ j(equal, &true_value);
1458 __ cmp(reg, Factory::undefined_value());
1459 __ j(equal, &true_value);
1460 __ test(reg, Immediate(kSmiTagMask));
1461 __ j(zero, &false_value);
1462 // Check for undetectable objects by looking in the bit field in
1463 // the map. The object has already been smi checked.
1464 Register scratch = result;
1465 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1466 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1467 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1468 __ j(not_zero, &true_value);
1469 __ bind(&false_value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001470 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001471 __ jmp(&done);
1472 __ bind(&true_value);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001473 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001474 __ bind(&done);
1475 }
1476}
1477
1478
1479void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001480 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001481
1482 // TODO(fsc): If the expression is known to be a smi, then it's
1483 // definitely not null. Jump to the false block.
1484
1485 int true_block = chunk_->LookupDestination(instr->true_block_id());
1486 int false_block = chunk_->LookupDestination(instr->false_block_id());
1487
1488 __ cmp(reg, Factory::null_value());
1489 if (instr->is_strict()) {
1490 EmitBranch(true_block, false_block, equal);
1491 } else {
1492 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1493 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1494 __ j(equal, true_label);
1495 __ cmp(reg, Factory::undefined_value());
1496 __ j(equal, true_label);
1497 __ test(reg, Immediate(kSmiTagMask));
1498 __ j(zero, false_label);
1499 // Check for undetectable objects by looking in the bit field in
1500 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001501 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001502 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1503 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1504 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1505 EmitBranch(true_block, false_block, not_zero);
1506 }
1507}
1508
1509
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001510Condition LCodeGen::EmitIsObject(Register input,
1511 Register temp1,
1512 Register temp2,
1513 Label* is_not_object,
1514 Label* is_object) {
1515 ASSERT(!input.is(temp1));
1516 ASSERT(!input.is(temp2));
1517 ASSERT(!temp1.is(temp2));
1518
1519 __ test(input, Immediate(kSmiTagMask));
1520 __ j(equal, is_not_object);
1521
1522 __ cmp(input, Factory::null_value());
1523 __ j(equal, is_object);
1524
1525 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1526 // Undetectable objects behave like undefined.
1527 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
1528 __ test(temp2, Immediate(1 << Map::kIsUndetectable));
1529 __ j(not_zero, is_not_object);
1530
1531 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
1532 __ cmp(temp2, FIRST_JS_OBJECT_TYPE);
1533 __ j(below, is_not_object);
1534 __ cmp(temp2, LAST_JS_OBJECT_TYPE);
1535 return below_equal;
1536}
1537
1538
1539void LCodeGen::DoIsObject(LIsObject* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001540 Register reg = ToRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001541 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001542 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001543 Label is_false, is_true, done;
1544
1545 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1546 __ j(true_cond, &is_true);
1547
1548 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001549 __ mov(result, Factory::false_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001550 __ jmp(&done);
1551
1552 __ bind(&is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001553 __ mov(result, Factory::true_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001554
1555 __ bind(&done);
1556}
1557
1558
1559void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001560 Register reg = ToRegister(instr->InputAt(0));
1561 Register temp = ToRegister(instr->TempAt(0));
1562 Register temp2 = ToRegister(instr->TempAt(1));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001563
1564 int true_block = chunk_->LookupDestination(instr->true_block_id());
1565 int false_block = chunk_->LookupDestination(instr->false_block_id());
1566 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1567 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1568
1569 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
1570
1571 EmitBranch(true_block, false_block, true_cond);
1572}
1573
1574
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001575void LCodeGen::DoIsSmi(LIsSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001576 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001577 Register result = ToRegister(instr->result());
1578
1579 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1580 __ test(input, Immediate(kSmiTagMask));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001581 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001582 NearLabel done;
1583 __ j(zero, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001584 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585 __ bind(&done);
1586}
1587
1588
1589void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001590 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001591
1592 int true_block = chunk_->LookupDestination(instr->true_block_id());
1593 int false_block = chunk_->LookupDestination(instr->false_block_id());
1594
1595 __ test(input, Immediate(kSmiTagMask));
1596 EmitBranch(true_block, false_block, zero);
1597}
1598
1599
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001600static InstanceType TestType(HHasInstanceType* instr) {
1601 InstanceType from = instr->from();
1602 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001603 if (from == FIRST_TYPE) return to;
1604 ASSERT(from == to || to == LAST_TYPE);
1605 return from;
1606}
1607
1608
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001609static Condition BranchCondition(HHasInstanceType* instr) {
1610 InstanceType from = instr->from();
1611 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001612 if (from == to) return equal;
1613 if (to == LAST_TYPE) return above_equal;
1614 if (from == FIRST_TYPE) return below_equal;
1615 UNREACHABLE();
1616 return equal;
1617}
1618
1619
1620void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001621 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001622 Register result = ToRegister(instr->result());
1623
1624 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1625 __ test(input, Immediate(kSmiTagMask));
1626 NearLabel done, is_false;
1627 __ j(zero, &is_false);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001628 __ CmpObjectType(input, TestType(instr->hydrogen()), result);
1629 __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001630 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001631 __ jmp(&done);
1632 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001633 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001634 __ bind(&done);
1635}
1636
1637
1638void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001639 Register input = ToRegister(instr->InputAt(0));
1640 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641
1642 int true_block = chunk_->LookupDestination(instr->true_block_id());
1643 int false_block = chunk_->LookupDestination(instr->false_block_id());
1644
1645 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1646
1647 __ test(input, Immediate(kSmiTagMask));
1648 __ j(zero, false_label);
1649
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001650 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1651 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652}
1653
1654
1655void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001656 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001657 Register result = ToRegister(instr->result());
1658
1659 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001660 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001661 __ test(FieldOperand(input, String::kHashFieldOffset),
1662 Immediate(String::kContainsCachedArrayIndexMask));
1663 NearLabel done;
1664 __ j(not_zero, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001665 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001666 __ bind(&done);
1667}
1668
1669
1670void LCodeGen::DoHasCachedArrayIndexAndBranch(
1671 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001672 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001673
1674 int true_block = chunk_->LookupDestination(instr->true_block_id());
1675 int false_block = chunk_->LookupDestination(instr->false_block_id());
1676
1677 __ test(FieldOperand(input, String::kHashFieldOffset),
1678 Immediate(String::kContainsCachedArrayIndexMask));
1679 EmitBranch(true_block, false_block, not_equal);
1680}
1681
1682
1683// Branches to a label or falls through with the answer in the z flag. Trashes
1684// the temp registers, but not the input. Only input and temp2 may alias.
1685void LCodeGen::EmitClassOfTest(Label* is_true,
1686 Label* is_false,
1687 Handle<String>class_name,
1688 Register input,
1689 Register temp,
1690 Register temp2) {
1691 ASSERT(!input.is(temp));
1692 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
1693 __ test(input, Immediate(kSmiTagMask));
1694 __ j(zero, is_false);
1695 __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
1696 __ j(below, is_false);
1697
1698 // Map is now in temp.
1699 // Functions have class 'Function'.
1700 __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
1701 if (class_name->IsEqualTo(CStrVector("Function"))) {
1702 __ j(equal, is_true);
1703 } else {
1704 __ j(equal, is_false);
1705 }
1706
1707 // Check if the constructor in the map is a function.
1708 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
1709
1710 // As long as JS_FUNCTION_TYPE is the last instance type and it is
1711 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1712 // LAST_JS_OBJECT_TYPE.
1713 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1714 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
1715
1716 // Objects with a non-function constructor have class 'Object'.
1717 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1718 if (class_name->IsEqualTo(CStrVector("Object"))) {
1719 __ j(not_equal, is_true);
1720 } else {
1721 __ j(not_equal, is_false);
1722 }
1723
1724 // temp now contains the constructor function. Grab the
1725 // instance class name from there.
1726 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1727 __ mov(temp, FieldOperand(temp,
1728 SharedFunctionInfo::kInstanceClassNameOffset));
1729 // The class name we are testing against is a symbol because it's a literal.
1730 // The name in the constructor is a symbol because of the way the context is
1731 // booted. This routine isn't expected to work for random API-created
1732 // classes and it doesn't have to because you can't access it with natives
1733 // syntax. Since both sides are symbols it is sufficient to use an identity
1734 // comparison.
1735 __ cmp(temp, class_name);
1736 // End with the answer in the z flag.
1737}
1738
1739
1740void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001741 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001742 Register result = ToRegister(instr->result());
1743 ASSERT(input.is(result));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001744 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001745 Handle<String> class_name = instr->hydrogen()->class_name();
1746 NearLabel done;
1747 Label is_true, is_false;
1748
1749 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
1750
1751 __ j(not_equal, &is_false);
1752
1753 __ bind(&is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001754 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001755 __ jmp(&done);
1756
1757 __ bind(&is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001758 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001759 __ bind(&done);
1760}
1761
1762
1763void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001764 Register input = ToRegister(instr->InputAt(0));
1765 Register temp = ToRegister(instr->TempAt(0));
1766 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001767 if (input.is(temp)) {
1768 // Swap.
1769 Register swapper = temp;
1770 temp = temp2;
1771 temp2 = swapper;
1772 }
1773 Handle<String> class_name = instr->hydrogen()->class_name();
1774
1775 int true_block = chunk_->LookupDestination(instr->true_block_id());
1776 int false_block = chunk_->LookupDestination(instr->false_block_id());
1777
1778 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1779 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1780
1781 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1782
1783 EmitBranch(true_block, false_block, equal);
1784}
1785
1786
1787void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001788 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001789 int true_block = instr->true_block_id();
1790 int false_block = instr->false_block_id();
1791
1792 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1793 EmitBranch(true_block, false_block, equal);
1794}
1795
1796
1797void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001798 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001799 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001800 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001801 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1802
1803 NearLabel true_value, done;
1804 __ test(eax, Operand(eax));
1805 __ j(zero, &true_value);
1806 __ mov(ToRegister(instr->result()), Factory::false_value());
1807 __ jmp(&done);
1808 __ bind(&true_value);
1809 __ mov(ToRegister(instr->result()), Factory::true_value());
1810 __ bind(&done);
1811}
1812
1813
1814void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001815 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001816 int true_block = chunk_->LookupDestination(instr->true_block_id());
1817 int false_block = chunk_->LookupDestination(instr->false_block_id());
1818
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001819 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001820 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1821 __ test(eax, Operand(eax));
1822 EmitBranch(true_block, false_block, zero);
1823}
1824
1825
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001826void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1827 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1828 public:
1829 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1830 LInstanceOfKnownGlobal* instr)
1831 : LDeferredCode(codegen), instr_(instr) { }
1832 virtual void Generate() {
1833 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
1834 }
1835
1836 Label* map_check() { return &map_check_; }
1837
1838 private:
1839 LInstanceOfKnownGlobal* instr_;
1840 Label map_check_;
1841 };
1842
1843 DeferredInstanceOfKnownGlobal* deferred;
1844 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1845
1846 Label done, false_result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001847 Register object = ToRegister(instr->InputAt(0));
1848 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001849
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001850 // A Smi is not an instance of anything.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001851 __ test(object, Immediate(kSmiTagMask));
1852 __ j(zero, &false_result, not_taken);
1853
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001854 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001855 // hole value will be patched to the last map/result pair generated by the
1856 // instanceof stub.
1857 NearLabel cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001858 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001859 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
1860 __ bind(deferred->map_check()); // Label for calculating code patching.
1861 __ cmp(map, Factory::the_hole_value()); // Patched to cached map.
1862 __ j(not_equal, &cache_miss, not_taken);
1863 __ mov(eax, Factory::the_hole_value()); // Patched to either true or false.
1864 __ jmp(&done);
1865
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001866 // The inlined call site cache did not match. Check for null and string
1867 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001868 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001869 // Null is not an instance of anything.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001870 __ cmp(object, Factory::null_value());
1871 __ j(equal, &false_result);
1872
1873 // String values are not instances of anything.
1874 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
1875 __ j(is_string, &false_result);
1876
1877 // Go to the deferred code.
1878 __ jmp(deferred->entry());
1879
1880 __ bind(&false_result);
1881 __ mov(ToRegister(instr->result()), Factory::false_value());
1882
1883 // Here result has either true or false. Deferred code also produces true or
1884 // false object.
1885 __ bind(deferred->exit());
1886 __ bind(&done);
1887}
1888
1889
1890void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
1891 Label* map_check) {
1892 __ PushSafepointRegisters();
1893
1894 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
1895 flags = static_cast<InstanceofStub::Flags>(
1896 flags | InstanceofStub::kArgsInRegisters);
1897 flags = static_cast<InstanceofStub::Flags>(
1898 flags | InstanceofStub::kCallSiteInlineCheck);
1899 flags = static_cast<InstanceofStub::Flags>(
1900 flags | InstanceofStub::kReturnTrueFalseObject);
1901 InstanceofStub stub(flags);
1902
1903 // Get the temp register reserved by the instruction. This needs to be edi as
1904 // its slot of the pushing of safepoint registers is used to communicate the
1905 // offset to the location of the map check.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001906 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001907 ASSERT(temp.is(edi));
1908 __ mov(InstanceofStub::right(), Immediate(instr->function()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001909 static const int kAdditionalDelta = 16;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001910 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
1911 Label before_push_delta;
1912 __ bind(&before_push_delta);
1913 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001914 __ StoreToSafepointRegisterSlot(temp, temp);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001915 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001916 __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
1917 ASSERT_EQ(kAdditionalDelta,
1918 masm_->SizeOfCodeGeneratedSince(&before_push_delta));
1919 RecordSafepointWithRegisters(
1920 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
1921 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001922 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001923 __ PopSafepointRegisters();
1924}
1925
1926
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001927static Condition ComputeCompareCondition(Token::Value op) {
1928 switch (op) {
1929 case Token::EQ_STRICT:
1930 case Token::EQ:
1931 return equal;
1932 case Token::LT:
1933 return less;
1934 case Token::GT:
1935 return greater;
1936 case Token::LTE:
1937 return less_equal;
1938 case Token::GTE:
1939 return greater_equal;
1940 default:
1941 UNREACHABLE();
1942 return no_condition;
1943 }
1944}
1945
1946
1947void LCodeGen::DoCmpT(LCmpT* instr) {
1948 Token::Value op = instr->op();
1949
1950 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001951 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001952
1953 Condition condition = ComputeCompareCondition(op);
1954 if (op == Token::GT || op == Token::LTE) {
1955 condition = ReverseCondition(condition);
1956 }
1957 NearLabel true_value, done;
1958 __ test(eax, Operand(eax));
1959 __ j(condition, &true_value);
1960 __ mov(ToRegister(instr->result()), Factory::false_value());
1961 __ jmp(&done);
1962 __ bind(&true_value);
1963 __ mov(ToRegister(instr->result()), Factory::true_value());
1964 __ bind(&done);
1965}
1966
1967
1968void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
1969 Token::Value op = instr->op();
1970 int true_block = chunk_->LookupDestination(instr->true_block_id());
1971 int false_block = chunk_->LookupDestination(instr->false_block_id());
1972
1973 Handle<Code> ic = CompareIC::GetUninitialized(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001974 CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975
1976 // The compare stub expects compare condition and the input operands
1977 // reversed for GT and LTE.
1978 Condition condition = ComputeCompareCondition(op);
1979 if (op == Token::GT || op == Token::LTE) {
1980 condition = ReverseCondition(condition);
1981 }
1982 __ test(eax, Operand(eax));
1983 EmitBranch(true_block, false_block, condition);
1984}
1985
1986
1987void LCodeGen::DoReturn(LReturn* instr) {
1988 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001989 // Preserve the return value on the stack and rely on the runtime call
1990 // to return the value in the same register. We're leaving the code
1991 // managed by the register allocator and tearing down the frame, it's
1992 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001993 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001994 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 __ CallRuntime(Runtime::kTraceExit, 1);
1996 }
1997 __ mov(esp, ebp);
1998 __ pop(ebp);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001999 __ Ret((ParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002000}
2001
2002
2003void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
2004 Register result = ToRegister(instr->result());
2005 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
2006 if (instr->hydrogen()->check_hole_value()) {
2007 __ cmp(result, Factory::the_hole_value());
2008 DeoptimizeIf(equal, instr->environment());
2009 }
2010}
2011
2012
2013void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002014 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002015 Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
2016
2017 // If the cell we are storing to contains the hole it could have
2018 // been deleted from the property dictionary. In that case, we need
2019 // to update the property details in the property dictionary to mark
2020 // it as no longer deleted. We deoptimize in that case.
2021 if (instr->hydrogen()->check_hole_value()) {
2022 __ cmp(cell_operand, Factory::the_hole_value());
2023 DeoptimizeIf(equal, instr->environment());
2024 }
2025
2026 // Store the value.
2027 __ mov(cell_operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002028}
2029
2030
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002031void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002032 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002033 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002034 __ mov(result, ContextOperand(context, instr->slot_index()));
2035}
2036
2037
2038void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2039 Register context = ToRegister(instr->context());
2040 Register value = ToRegister(instr->value());
2041 __ mov(ContextOperand(context, instr->slot_index()), value);
2042 if (instr->needs_write_barrier()) {
2043 Register temp = ToRegister(instr->TempAt(0));
2044 int offset = Context::SlotOffset(instr->slot_index());
2045 __ RecordWrite(context, offset, value, temp);
2046 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002047}
2048
2049
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002050void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002051 Register object = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002052 Register result = ToRegister(instr->result());
2053 if (instr->hydrogen()->is_in_object()) {
2054 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2055 } else {
2056 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2057 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2058 }
2059}
2060
2061
2062void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002063 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002064 ASSERT(ToRegister(instr->object()).is(eax));
2065 ASSERT(ToRegister(instr->result()).is(eax));
2066
2067 __ mov(ecx, instr->name());
2068 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2069 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2070}
2071
2072
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002073void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2074 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002075 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002076 Register result = ToRegister(instr->result());
2077
2078 // Check that the function really is a function.
2079 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2080 DeoptimizeIf(not_equal, instr->environment());
2081
2082 // Check whether the function has an instance prototype.
2083 NearLabel non_instance;
2084 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2085 1 << Map::kHasNonInstancePrototype);
2086 __ j(not_zero, &non_instance);
2087
2088 // Get the prototype or initial map from the function.
2089 __ mov(result,
2090 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2091
2092 // Check that the function has a prototype or an initial map.
2093 __ cmp(Operand(result), Immediate(Factory::the_hole_value()));
2094 DeoptimizeIf(equal, instr->environment());
2095
2096 // If the function does not have an initial map, we're done.
2097 NearLabel done;
2098 __ CmpObjectType(result, MAP_TYPE, temp);
2099 __ j(not_equal, &done);
2100
2101 // Get the prototype from the initial map.
2102 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
2103 __ jmp(&done);
2104
2105 // Non-instance prototype: Fetch prototype from constructor field
2106 // in the function's map.
2107 __ bind(&non_instance);
2108 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2109
2110 // All done.
2111 __ bind(&done);
2112}
2113
2114
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002115void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002116 Register result = ToRegister(instr->result());
2117 Register input = ToRegister(instr->InputAt(0));
2118 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002119 if (FLAG_debug_code) {
2120 NearLabel done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002121 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122 Immediate(Factory::fixed_array_map()));
2123 __ j(equal, &done);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002124 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
2125 Immediate(Factory::pixel_array_map()));
2126 __ j(equal, &done);
2127 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002128 Immediate(Factory::fixed_cow_array_map()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002129 __ Check(equal, "Check for fast elements or pixel array failed.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002130 __ bind(&done);
2131 }
2132}
2133
2134
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002135void LCodeGen::DoLoadPixelArrayExternalPointer(
2136 LLoadPixelArrayExternalPointer* instr) {
2137 Register result = ToRegister(instr->result());
2138 Register input = ToRegister(instr->InputAt(0));
2139 __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
2140}
2141
2142
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2144 Register arguments = ToRegister(instr->arguments());
2145 Register length = ToRegister(instr->length());
2146 Operand index = ToOperand(instr->index());
2147 Register result = ToRegister(instr->result());
2148
2149 __ sub(length, index);
2150 DeoptimizeIf(below_equal, instr->environment());
2151
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002152 // There are two words between the frame pointer and the last argument.
2153 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002154 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2155}
2156
2157
2158void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
2159 Register elements = ToRegister(instr->elements());
2160 Register key = ToRegister(instr->key());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002161 Register result = ToRegister(instr->result());
2162 ASSERT(result.is(elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002163
2164 // Load the result.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002165 __ mov(result, FieldOperand(elements,
2166 key,
2167 times_pointer_size,
2168 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002170 // Check for the hole value.
2171 __ cmp(result, Factory::the_hole_value());
2172 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002173}
2174
2175
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002176void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002177 Register external_pointer = ToRegister(instr->external_pointer());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002178 Register key = ToRegister(instr->key());
2179 Register result = ToRegister(instr->result());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002180 ASSERT(result.is(external_pointer));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002181
2182 // Load the result.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002183 __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002184}
2185
2186
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002187void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002188 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002189 ASSERT(ToRegister(instr->object()).is(edx));
2190 ASSERT(ToRegister(instr->key()).is(eax));
2191
2192 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
2193 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2194}
2195
2196
2197void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2198 Register result = ToRegister(instr->result());
2199
2200 // Check for arguments adapter frame.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002201 NearLabel done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002202 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2203 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2204 __ cmp(Operand(result),
2205 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2206 __ j(equal, &adapted);
2207
2208 // No arguments adaptor frame.
2209 __ mov(result, Operand(ebp));
2210 __ jmp(&done);
2211
2212 // Arguments adaptor frame present.
2213 __ bind(&adapted);
2214 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2215
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002216 // Result is the frame pointer for the frame if not adapted and for the real
2217 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002218 __ bind(&done);
2219}
2220
2221
2222void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002223 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002224 Register result = ToRegister(instr->result());
2225
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002226 NearLabel done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002227
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002228 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002229 __ cmp(ebp, elem);
2230 __ mov(result, Immediate(scope()->num_parameters()));
2231 __ j(equal, &done);
2232
2233 // Arguments adaptor frame present. Get argument length from there.
2234 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2235 __ mov(result, Operand(result,
2236 ArgumentsAdaptorFrameConstants::kLengthOffset));
2237 __ SmiUntag(result);
2238
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002239 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002240 __ bind(&done);
2241}
2242
2243
2244void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2245 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002246 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002247 Register length = ToRegister(instr->length());
2248 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002249 Register scratch = ToRegister(instr->TempAt(0));
2250 ASSERT(receiver.is(eax)); // Used for parameter count.
2251 ASSERT(function.is(edi)); // Required by InvokeFunction.
2252 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002253
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002254 // If the receiver is null or undefined, we have to pass the global object
2255 // as a receiver.
2256 NearLabel global_object, receiver_ok;
2257 __ cmp(receiver, Factory::null_value());
2258 __ j(equal, &global_object);
2259 __ cmp(receiver, Factory::undefined_value());
2260 __ j(equal, &global_object);
2261
2262 // The receiver should be a JS object.
2263 __ test(receiver, Immediate(kSmiTagMask));
2264 DeoptimizeIf(equal, instr->environment());
2265 __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch);
2266 DeoptimizeIf(below, instr->environment());
2267 __ jmp(&receiver_ok);
2268
2269 __ bind(&global_object);
2270 // TODO(kmillikin): We have a hydrogen value for the global object. See
2271 // if it's better to use it than to explicitly fetch it from the context
2272 // here.
2273 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2274 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
2275 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002276
2277 // Copy the arguments to this function possibly from the
2278 // adaptor frame below it.
2279 const uint32_t kArgumentsLimit = 1 * KB;
2280 __ cmp(length, kArgumentsLimit);
2281 DeoptimizeIf(above, instr->environment());
2282
2283 __ push(receiver);
2284 __ mov(receiver, length);
2285
2286 // Loop through the arguments pushing them onto the execution
2287 // stack.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002288 NearLabel invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002289 // length is a small non-negative integer, due to the test above.
2290 __ test(length, Operand(length));
2291 __ j(zero, &invoke);
2292 __ bind(&loop);
2293 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2294 __ dec(length);
2295 __ j(not_zero, &loop);
2296
2297 // Invoke the function.
2298 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002299 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2300 LPointerMap* pointers = instr->pointer_map();
2301 LEnvironment* env = instr->deoptimization_environment();
2302 RecordPosition(pointers->position());
2303 RegisterEnvironmentForDeoptimization(env);
2304 SafepointGenerator safepoint_generator(this,
2305 pointers,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002306 env->deoptimization_index(),
2307 true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002308 v8::internal::ParameterCount actual(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002309 __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002310}
2311
2312
2313void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002314 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002315 if (argument->IsConstantOperand()) {
2316 __ push(ToImmediate(argument));
2317 } else {
2318 __ push(ToOperand(argument));
2319 }
2320}
2321
2322
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002323void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002324 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002325 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002326}
2327
2328
2329void LCodeGen::DoOuterContext(LOuterContext* instr) {
2330 Register context = ToRegister(instr->context());
2331 Register result = ToRegister(instr->result());
2332 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2333 __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
2334}
2335
2336
2337void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2338 Register context = ToRegister(instr->context());
2339 Register result = ToRegister(instr->result());
2340 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002341}
2342
2343
2344void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002345 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002346 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002347 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002348}
2349
2350
2351void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2352 int arity,
2353 LInstruction* instr) {
2354 // Change context if needed.
2355 bool change_context =
2356 (graph()->info()->closure()->context() != function->context()) ||
2357 scope()->contains_with() ||
2358 (scope()->num_heap_slots() > 0);
2359 if (change_context) {
2360 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002361 } else {
2362 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002363 }
2364
2365 // Set eax to arguments count if adaption is not needed. Assumes that eax
2366 // is available to write to at this point.
2367 if (!function->NeedsArgumentsAdaption()) {
2368 __ mov(eax, arity);
2369 }
2370
2371 LPointerMap* pointers = instr->pointer_map();
2372 RecordPosition(pointers->position());
2373
2374 // Invoke function.
2375 if (*function == *graph()->info()->closure()) {
2376 __ CallSelf();
2377 } else {
2378 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002379 EnsureRelocSpaceForDeoptimization();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002380 }
2381
2382 // Setup deoptimization.
2383 RegisterLazyDeoptimization(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002384}
2385
2386
2387void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2388 ASSERT(ToRegister(instr->result()).is(eax));
2389 __ mov(edi, instr->function());
2390 CallKnownFunction(instr->function(), instr->arity(), instr);
2391}
2392
2393
2394void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002395 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002396 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
2397 Factory::heap_number_map());
2398 DeoptimizeIf(not_equal, instr->environment());
2399
2400 Label done;
2401 Register tmp = input_reg.is(eax) ? ecx : eax;
2402 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2403
2404 // Preserve the value of all registers.
2405 __ PushSafepointRegisters();
2406
2407 Label negative;
2408 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002409 // Check the sign of the argument. If the argument is positive, just
2410 // return it. We do not need to patch the stack since |input| and
2411 // |result| are the same register and |input| will be restored
2412 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002413 __ test(tmp, Immediate(HeapNumber::kSignMask));
2414 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002415 __ jmp(&done);
2416
2417 __ bind(&negative);
2418
2419 Label allocated, slow;
2420 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2421 __ jmp(&allocated);
2422
2423 // Slow case: Call the runtime system to do the number allocation.
2424 __ bind(&slow);
2425
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002426 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002427 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
2428 RecordSafepointWithRegisters(
2429 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
2430 // Set the pointer to the new heap number in tmp.
2431 if (!tmp.is(eax)) __ mov(tmp, eax);
2432
2433 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002434 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002435
2436 __ bind(&allocated);
2437 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2438 __ and_(tmp2, ~HeapNumber::kSignMask);
2439 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2440 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2441 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002442 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002443
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002444 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002445 __ PopSafepointRegisters();
2446}
2447
2448
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002449void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2450 Register input_reg = ToRegister(instr->InputAt(0));
2451 __ test(input_reg, Operand(input_reg));
2452 Label is_positive;
2453 __ j(not_sign, &is_positive);
2454 __ neg(input_reg);
2455 __ test(input_reg, Operand(input_reg));
2456 DeoptimizeIf(negative, instr->environment());
2457 __ bind(&is_positive);
2458}
2459
2460
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002461void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2462 // Class for deferred case.
2463 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2464 public:
2465 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2466 LUnaryMathOperation* instr)
2467 : LDeferredCode(codegen), instr_(instr) { }
2468 virtual void Generate() {
2469 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2470 }
2471 private:
2472 LUnaryMathOperation* instr_;
2473 };
2474
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002475 ASSERT(instr->InputAt(0)->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002476 Representation r = instr->hydrogen()->value()->representation();
2477
2478 if (r.IsDouble()) {
2479 XMMRegister scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002480 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002481 __ pxor(scratch, scratch);
2482 __ subsd(scratch, input_reg);
2483 __ pand(input_reg, scratch);
2484 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002485 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002486 } else { // Tagged case.
2487 DeferredMathAbsTaggedHeapNumber* deferred =
2488 new DeferredMathAbsTaggedHeapNumber(this, instr);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002489 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002490 // Smi check.
2491 __ test(input_reg, Immediate(kSmiTagMask));
2492 __ j(not_zero, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002493 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002494 __ bind(deferred->exit());
2495 }
2496}
2497
2498
2499void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2500 XMMRegister xmm_scratch = xmm0;
2501 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002502 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2504 __ ucomisd(input_reg, xmm_scratch);
2505
2506 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2507 DeoptimizeIf(below_equal, instr->environment());
2508 } else {
2509 DeoptimizeIf(below, instr->environment());
2510 }
2511
2512 // Use truncating instruction (OK because input is positive).
2513 __ cvttsd2si(output_reg, Operand(input_reg));
2514
2515 // Overflow is signalled with minint.
2516 __ cmp(output_reg, 0x80000000u);
2517 DeoptimizeIf(equal, instr->environment());
2518}
2519
2520
2521void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2522 XMMRegister xmm_scratch = xmm0;
2523 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002524 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002525
2526 // xmm_scratch = 0.5
2527 ExternalReference one_half = ExternalReference::address_of_one_half();
2528 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
2529
2530 // input = input + 0.5
2531 __ addsd(input_reg, xmm_scratch);
2532
2533 // We need to return -0 for the input range [-0.5, 0[, otherwise
2534 // compute Math.floor(value + 0.5).
2535 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2536 __ ucomisd(input_reg, xmm_scratch);
2537 DeoptimizeIf(below_equal, instr->environment());
2538 } else {
2539 // If we don't need to bailout on -0, we check only bailout
2540 // on negative inputs.
2541 __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
2542 __ ucomisd(input_reg, xmm_scratch);
2543 DeoptimizeIf(below, instr->environment());
2544 }
2545
2546 // Compute Math.floor(value + 0.5).
2547 // Use truncating instruction (OK because input is positive).
2548 __ cvttsd2si(output_reg, Operand(input_reg));
2549
2550 // Overflow is signalled with minint.
2551 __ cmp(output_reg, 0x80000000u);
2552 DeoptimizeIf(equal, instr->environment());
2553}
2554
2555
2556void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002557 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002558 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2559 __ sqrtsd(input_reg, input_reg);
2560}
2561
2562
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002563void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2564 XMMRegister xmm_scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002565 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002566 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002567 __ xorpd(xmm_scratch, xmm_scratch);
2568 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002569 __ sqrtsd(input_reg, input_reg);
2570}
2571
2572
2573void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002574 LOperand* left = instr->InputAt(0);
2575 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002576 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2577 Representation exponent_type = instr->hydrogen()->right()->representation();
2578 if (exponent_type.IsDouble()) {
2579 // It is safe to use ebx directly since the instruction is marked
2580 // as a call.
2581 __ PrepareCallCFunction(4, ebx);
2582 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2583 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
2584 __ CallCFunction(ExternalReference::power_double_double_function(), 4);
2585 } else if (exponent_type.IsInteger32()) {
2586 // It is safe to use ebx directly since the instruction is marked
2587 // as a call.
2588 ASSERT(!ToRegister(right).is(ebx));
2589 __ PrepareCallCFunction(4, ebx);
2590 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2591 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
2592 __ CallCFunction(ExternalReference::power_double_int_function(), 4);
2593 } else {
2594 ASSERT(exponent_type.IsTagged());
2595 CpuFeatures::Scope scope(SSE2);
2596 Register right_reg = ToRegister(right);
2597
2598 Label non_smi, call;
2599 __ test(right_reg, Immediate(kSmiTagMask));
2600 __ j(not_zero, &non_smi);
2601 __ SmiUntag(right_reg);
2602 __ cvtsi2sd(result_reg, Operand(right_reg));
2603 __ jmp(&call);
2604
2605 __ bind(&non_smi);
2606 // It is safe to use ebx directly since the instruction is marked
2607 // as a call.
2608 ASSERT(!right_reg.is(ebx));
2609 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
2610 DeoptimizeIf(not_equal, instr->environment());
2611 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
2612
2613 __ bind(&call);
2614 __ PrepareCallCFunction(4, ebx);
2615 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2616 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
2617 __ CallCFunction(ExternalReference::power_double_double_function(), 4);
2618 }
2619
2620 // Return value is in st(0) on ia32.
2621 // Store it into the (fixed) result register.
2622 __ sub(Operand(esp), Immediate(kDoubleSize));
2623 __ fstp_d(Operand(esp, 0));
2624 __ movdbl(result_reg, Operand(esp, 0));
2625 __ add(Operand(esp), Immediate(kDoubleSize));
2626}
2627
2628
2629void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
2630 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org023421e2010-12-21 12:19:12 +00002631 TranscendentalCacheStub stub(TranscendentalCache::LOG,
2632 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002633 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002634}
2635
2636
2637void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
2638 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2639 TranscendentalCacheStub stub(TranscendentalCache::COS,
2640 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002641 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
whesse@chromium.org023421e2010-12-21 12:19:12 +00002642}
2643
2644
2645void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
2646 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
2647 TranscendentalCacheStub stub(TranscendentalCache::SIN,
2648 TranscendentalCacheStub::UNTAGGED);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002649 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002650}
2651
2652
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002653void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
2654 switch (instr->op()) {
2655 case kMathAbs:
2656 DoMathAbs(instr);
2657 break;
2658 case kMathFloor:
2659 DoMathFloor(instr);
2660 break;
2661 case kMathRound:
2662 DoMathRound(instr);
2663 break;
2664 case kMathSqrt:
2665 DoMathSqrt(instr);
2666 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002667 case kMathPowHalf:
2668 DoMathPowHalf(instr);
2669 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00002670 case kMathCos:
2671 DoMathCos(instr);
2672 break;
2673 case kMathSin:
2674 DoMathSin(instr);
2675 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002676 case kMathLog:
2677 DoMathLog(instr);
2678 break;
2679
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002680 default:
2681 UNREACHABLE();
2682 }
2683}
2684
2685
2686void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002687 ASSERT(ToRegister(instr->context()).is(esi));
2688 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002689 ASSERT(ToRegister(instr->result()).is(eax));
2690
2691 int arity = instr->arity();
2692 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
2693 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002694}
2695
2696
2697void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002698 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002699 ASSERT(ToRegister(instr->result()).is(eax));
2700
2701 int arity = instr->arity();
2702 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
2703 __ mov(ecx, instr->name());
2704 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002705}
2706
2707
2708void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002709 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002710 ASSERT(ToRegister(instr->result()).is(eax));
2711
2712 int arity = instr->arity();
2713 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
2714 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2715 __ Drop(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002716}
2717
2718
2719void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002720 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002721 ASSERT(ToRegister(instr->result()).is(eax));
2722
2723 int arity = instr->arity();
2724 Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
2725 __ mov(ecx, instr->name());
2726 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727}
2728
2729
2730void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
2731 ASSERT(ToRegister(instr->result()).is(eax));
2732 __ mov(edi, instr->target());
2733 CallKnownFunction(instr->target(), instr->arity(), instr);
2734}
2735
2736
2737void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002738 ASSERT(ToRegister(instr->context()).is(esi));
2739 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002740 ASSERT(ToRegister(instr->result()).is(eax));
2741
2742 Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
2743 __ Set(eax, Immediate(instr->arity()));
2744 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
2745}
2746
2747
2748void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002749 CallRuntime(instr->function(), instr->arity(), instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002750}
2751
2752
2753void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
2754 Register object = ToRegister(instr->object());
2755 Register value = ToRegister(instr->value());
2756 int offset = instr->offset();
2757
2758 if (!instr->transition().is_null()) {
2759 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
2760 }
2761
2762 // Do the store.
2763 if (instr->is_in_object()) {
2764 __ mov(FieldOperand(object, offset), value);
2765 if (instr->needs_write_barrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002766 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002767 // Update the write barrier for the object for in-object properties.
2768 __ RecordWrite(object, offset, value, temp);
2769 }
2770 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002771 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002772 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
2773 __ mov(FieldOperand(temp, offset), value);
2774 if (instr->needs_write_barrier()) {
2775 // Update the write barrier for the properties array.
2776 // object is used as a scratch register.
2777 __ RecordWrite(temp, offset, value, object);
2778 }
2779 }
2780}
2781
2782
2783void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002784 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002785 ASSERT(ToRegister(instr->object()).is(edx));
2786 ASSERT(ToRegister(instr->value()).is(eax));
2787
2788 __ mov(ecx, instr->name());
2789 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
2790 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2791}
2792
2793
2794void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
2795 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
2796 DeoptimizeIf(above_equal, instr->environment());
2797}
2798
2799
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002800void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
2801 Register external_pointer = ToRegister(instr->external_pointer());
2802 Register key = ToRegister(instr->key());
2803 Register value = ToRegister(instr->value());
2804 ASSERT(ToRegister(instr->TempAt(0)).is(eax));
2805
2806 __ mov(eax, value);
2807 { // Clamp the value to [0..255].
2808 NearLabel done;
2809 __ test(eax, Immediate(0xFFFFFF00));
2810 __ j(zero, &done);
2811 __ setcc(negative, eax); // 1 if negative, 0 if positive.
2812 __ dec_b(eax); // 0 if negative, 255 if positive.
2813 __ bind(&done);
2814 }
2815 __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
2816}
2817
2818
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002819void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
2820 Register value = ToRegister(instr->value());
2821 Register elements = ToRegister(instr->object());
2822 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
2823
2824 // Do the store.
2825 if (instr->key()->IsConstantOperand()) {
2826 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
2827 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
2828 int offset =
2829 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
2830 __ mov(FieldOperand(elements, offset), value);
2831 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002832 __ mov(FieldOperand(elements,
2833 key,
2834 times_pointer_size,
2835 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002836 value);
2837 }
2838
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002839 if (instr->hydrogen()->NeedsWriteBarrier()) {
2840 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002841 __ lea(key,
2842 FieldOperand(elements,
2843 key,
2844 times_pointer_size,
2845 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002846 __ RecordWrite(elements, key, value);
2847 }
2848}
2849
2850
2851void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002852 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002853 ASSERT(ToRegister(instr->object()).is(edx));
2854 ASSERT(ToRegister(instr->key()).is(ecx));
2855 ASSERT(ToRegister(instr->value()).is(eax));
2856
2857 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
2858 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2859}
2860
2861
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002862void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
2863 class DeferredStringCharCodeAt: public LDeferredCode {
2864 public:
2865 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
2866 : LDeferredCode(codegen), instr_(instr) { }
2867 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
2868 private:
2869 LStringCharCodeAt* instr_;
2870 };
2871
2872 Register string = ToRegister(instr->string());
2873 Register index = no_reg;
2874 int const_index = -1;
2875 if (instr->index()->IsConstantOperand()) {
2876 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2877 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
2878 if (!Smi::IsValid(const_index)) {
2879 // Guaranteed to be out of bounds because of the assert above.
2880 // So the bounds check that must dominate this instruction must
2881 // have deoptimized already.
2882 if (FLAG_debug_code) {
2883 __ Abort("StringCharCodeAt: out of bounds index.");
2884 }
2885 // No code needs to be generated.
2886 return;
2887 }
2888 } else {
2889 index = ToRegister(instr->index());
2890 }
2891 Register result = ToRegister(instr->result());
2892
2893 DeferredStringCharCodeAt* deferred =
2894 new DeferredStringCharCodeAt(this, instr);
2895
2896 NearLabel flat_string, ascii_string, done;
2897
2898 // Fetch the instance type of the receiver into result register.
2899 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
2900 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
2901
2902 // We need special handling for non-flat strings.
2903 STATIC_ASSERT(kSeqStringTag == 0);
2904 __ test(result, Immediate(kStringRepresentationMask));
2905 __ j(zero, &flat_string);
2906
2907 // Handle non-flat strings.
2908 __ test(result, Immediate(kIsConsStringMask));
2909 __ j(zero, deferred->entry());
2910
2911 // ConsString.
2912 // Check whether the right hand side is the empty string (i.e. if
2913 // this is really a flat string in a cons string). If that is not
2914 // the case we would rather go to the runtime system now to flatten
2915 // the string.
2916 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
2917 Immediate(Factory::empty_string()));
2918 __ j(not_equal, deferred->entry());
2919 // Get the first of the two strings and load its instance type.
2920 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
2921 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
2922 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
2923 // If the first cons component is also non-flat, then go to runtime.
2924 STATIC_ASSERT(kSeqStringTag == 0);
2925 __ test(result, Immediate(kStringRepresentationMask));
2926 __ j(not_zero, deferred->entry());
2927
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002928 // Check for ASCII or two-byte string.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002929 __ bind(&flat_string);
2930 STATIC_ASSERT(kAsciiStringTag != 0);
2931 __ test(result, Immediate(kStringEncodingMask));
2932 __ j(not_zero, &ascii_string);
2933
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002934 // Two-byte string.
2935 // Load the two-byte character code into the result register.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002936 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2937 if (instr->index()->IsConstantOperand()) {
2938 __ movzx_w(result,
2939 FieldOperand(string,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002940 SeqTwoByteString::kHeaderSize +
2941 (kUC16Size * const_index)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002942 } else {
2943 __ movzx_w(result, FieldOperand(string,
2944 index,
2945 times_2,
2946 SeqTwoByteString::kHeaderSize));
2947 }
2948 __ jmp(&done);
2949
2950 // ASCII string.
2951 // Load the byte into the result register.
2952 __ bind(&ascii_string);
2953 if (instr->index()->IsConstantOperand()) {
2954 __ movzx_b(result, FieldOperand(string,
2955 SeqAsciiString::kHeaderSize + const_index));
2956 } else {
2957 __ movzx_b(result, FieldOperand(string,
2958 index,
2959 times_1,
2960 SeqAsciiString::kHeaderSize));
2961 }
2962 __ bind(&done);
2963 __ bind(deferred->exit());
2964}
2965
2966
2967void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
2968 Register string = ToRegister(instr->string());
2969 Register result = ToRegister(instr->result());
2970
2971 // TODO(3095996): Get rid of this. For now, we need to make the
2972 // result register contain a valid pointer because it is already
2973 // contained in the register pointer map.
2974 __ Set(result, Immediate(0));
2975
2976 __ PushSafepointRegisters();
2977 __ push(string);
2978 // Push the index as a smi. This is safe because of the checks in
2979 // DoStringCharCodeAt above.
2980 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
2981 if (instr->index()->IsConstantOperand()) {
2982 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2983 __ push(Immediate(Smi::FromInt(const_index)));
2984 } else {
2985 Register index = ToRegister(instr->index());
2986 __ SmiTag(index);
2987 __ push(index);
2988 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002989 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002990 __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
2991 RecordSafepointWithRegisters(
2992 instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
2993 if (FLAG_debug_code) {
2994 __ AbortIfNotSmi(eax);
2995 }
2996 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002997 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002998 __ PopSafepointRegisters();
2999}
3000
3001
3002void LCodeGen::DoStringLength(LStringLength* instr) {
3003 Register string = ToRegister(instr->string());
3004 Register result = ToRegister(instr->result());
3005 __ mov(result, FieldOperand(string, String::kLengthOffset));
3006}
3007
3008
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003009void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003010 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003011 ASSERT(input->IsRegister() || input->IsStackSlot());
3012 LOperand* output = instr->result();
3013 ASSERT(output->IsDoubleRegister());
3014 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3015}
3016
3017
3018void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3019 class DeferredNumberTagI: public LDeferredCode {
3020 public:
3021 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3022 : LDeferredCode(codegen), instr_(instr) { }
3023 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
3024 private:
3025 LNumberTagI* instr_;
3026 };
3027
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003028 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003029 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3030 Register reg = ToRegister(input);
3031
3032 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3033 __ SmiTag(reg);
3034 __ j(overflow, deferred->entry());
3035 __ bind(deferred->exit());
3036}
3037
3038
3039void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3040 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003041 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003042 Register tmp = reg.is(eax) ? ecx : eax;
3043
3044 // Preserve the value of all registers.
3045 __ PushSafepointRegisters();
3046
3047 // There was overflow, so bits 30 and 31 of the original integer
3048 // disagree. Try to allocate a heap number in new space and store
3049 // the value in there. If that fails, call the runtime system.
3050 NearLabel done;
3051 __ SmiUntag(reg);
3052 __ xor_(reg, 0x80000000);
3053 __ cvtsi2sd(xmm0, Operand(reg));
3054 if (FLAG_inline_new) {
3055 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
3056 __ jmp(&done);
3057 }
3058
3059 // Slow case: Call the runtime system to do the number allocation.
3060 __ bind(&slow);
3061
3062 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3063 // register is stored, as this register is in the pointer map, but contains an
3064 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003065 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003066
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003067 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003068 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3069 RecordSafepointWithRegisters(
3070 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
3071 if (!reg.is(eax)) __ mov(reg, eax);
3072
3073 // Done. Put the value in xmm0 into the value of the allocated heap
3074 // number.
3075 __ bind(&done);
3076 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003077 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003078 __ PopSafepointRegisters();
3079}
3080
3081
3082void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3083 class DeferredNumberTagD: public LDeferredCode {
3084 public:
3085 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3086 : LDeferredCode(codegen), instr_(instr) { }
3087 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
3088 private:
3089 LNumberTagD* instr_;
3090 };
3091
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003092 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003093 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003094 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095
3096 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3097 if (FLAG_inline_new) {
3098 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3099 } else {
3100 __ jmp(deferred->entry());
3101 }
3102 __ bind(deferred->exit());
3103 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3104}
3105
3106
3107void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3108 // TODO(3095996): Get rid of this. For now, we need to make the
3109 // result register contain a valid pointer because it is already
3110 // contained in the register pointer map.
3111 Register reg = ToRegister(instr->result());
3112 __ Set(reg, Immediate(0));
3113
3114 __ PushSafepointRegisters();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003115 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003116 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3117 RecordSafepointWithRegisters(
3118 instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003119 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003120 __ PopSafepointRegisters();
3121}
3122
3123
3124void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003125 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003126 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3127 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3128 __ SmiTag(ToRegister(input));
3129}
3130
3131
3132void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003133 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003134 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3135 if (instr->needs_check()) {
3136 __ test(ToRegister(input), Immediate(kSmiTagMask));
3137 DeoptimizeIf(not_zero, instr->environment());
3138 }
3139 __ SmiUntag(ToRegister(input));
3140}
3141
3142
3143void LCodeGen::EmitNumberUntagD(Register input_reg,
3144 XMMRegister result_reg,
3145 LEnvironment* env) {
3146 NearLabel load_smi, heap_number, done;
3147
3148 // Smi check.
3149 __ test(input_reg, Immediate(kSmiTagMask));
3150 __ j(zero, &load_smi, not_taken);
3151
3152 // Heap number map check.
3153 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3154 Factory::heap_number_map());
3155 __ j(equal, &heap_number);
3156
3157 __ cmp(input_reg, Factory::undefined_value());
3158 DeoptimizeIf(not_equal, env);
3159
3160 // Convert undefined to NaN.
3161 __ push(input_reg);
3162 __ mov(input_reg, Factory::nan_value());
3163 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3164 __ pop(input_reg);
3165 __ jmp(&done);
3166
3167 // Heap number to XMM conversion.
3168 __ bind(&heap_number);
3169 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
3170 __ jmp(&done);
3171
3172 // Smi to XMM conversion
3173 __ bind(&load_smi);
3174 __ SmiUntag(input_reg); // Untag smi before converting to float.
3175 __ cvtsi2sd(result_reg, Operand(input_reg));
3176 __ SmiTag(input_reg); // Retag smi.
3177 __ bind(&done);
3178}
3179
3180
3181class DeferredTaggedToI: public LDeferredCode {
3182 public:
3183 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3184 : LDeferredCode(codegen), instr_(instr) { }
3185 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3186 private:
3187 LTaggedToI* instr_;
3188};
3189
3190
3191void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
3192 NearLabel done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003193 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003194
3195 // Heap number map check.
3196 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
3197 Factory::heap_number_map());
3198
3199 if (instr->truncating()) {
3200 __ j(equal, &heap_number);
3201 // Check for undefined. Undefined is converted to zero for truncating
3202 // conversions.
3203 __ cmp(input_reg, Factory::undefined_value());
3204 DeoptimizeIf(not_equal, instr->environment());
3205 __ mov(input_reg, 0);
3206 __ jmp(&done);
3207
3208 __ bind(&heap_number);
3209 if (CpuFeatures::IsSupported(SSE3)) {
3210 CpuFeatures::Scope scope(SSE3);
3211 NearLabel convert;
3212 // Use more powerful conversion when sse3 is available.
3213 // Load x87 register with heap number.
3214 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3215 // Get exponent alone and check for too-big exponent.
3216 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3217 __ and_(input_reg, HeapNumber::kExponentMask);
3218 const uint32_t kTooBigExponent =
3219 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3220 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
3221 __ j(less, &convert);
3222 // Pop FPU stack before deoptimizing.
3223 __ ffree(0);
3224 __ fincstp();
3225 DeoptimizeIf(no_condition, instr->environment());
3226
3227 // Reserve space for 64 bit answer.
3228 __ bind(&convert);
3229 __ sub(Operand(esp), Immediate(kDoubleSize));
3230 // Do conversion, which cannot fail because we checked the exponent.
3231 __ fisttp_d(Operand(esp, 0));
3232 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3233 __ add(Operand(esp), Immediate(kDoubleSize));
3234 } else {
3235 NearLabel deopt;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003236 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003237 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3238 __ cvttsd2si(input_reg, Operand(xmm0));
3239 __ cmp(input_reg, 0x80000000u);
3240 __ j(not_equal, &done);
3241 // Check if the input was 0x8000000 (kMinInt).
3242 // If no, then we got an overflow and we deoptimize.
3243 ExternalReference min_int = ExternalReference::address_of_min_int();
3244 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3245 __ ucomisd(xmm_temp, xmm0);
3246 DeoptimizeIf(not_equal, instr->environment());
3247 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3248 }
3249 } else {
3250 // Deoptimize if we don't have a heap number.
3251 DeoptimizeIf(not_equal, instr->environment());
3252
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003253 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003254 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3255 __ cvttsd2si(input_reg, Operand(xmm0));
3256 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3257 __ ucomisd(xmm0, xmm_temp);
3258 DeoptimizeIf(not_equal, instr->environment());
3259 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3260 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3261 __ test(input_reg, Operand(input_reg));
3262 __ j(not_zero, &done);
3263 __ movmskpd(input_reg, xmm0);
3264 __ and_(input_reg, 1);
3265 DeoptimizeIf(not_zero, instr->environment());
3266 }
3267 }
3268 __ bind(&done);
3269}
3270
3271
3272void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003273 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003274 ASSERT(input->IsRegister());
3275 ASSERT(input->Equals(instr->result()));
3276
3277 Register input_reg = ToRegister(input);
3278
3279 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3280
3281 // Smi check.
3282 __ test(input_reg, Immediate(kSmiTagMask));
3283 __ j(not_zero, deferred->entry());
3284
3285 // Smi to int32 conversion
3286 __ SmiUntag(input_reg); // Untag smi.
3287
3288 __ bind(deferred->exit());
3289}
3290
3291
3292void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003293 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294 ASSERT(input->IsRegister());
3295 LOperand* result = instr->result();
3296 ASSERT(result->IsDoubleRegister());
3297
3298 Register input_reg = ToRegister(input);
3299 XMMRegister result_reg = ToDoubleRegister(result);
3300
3301 EmitNumberUntagD(input_reg, result_reg, instr->environment());
3302}
3303
3304
3305void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003306 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003307 ASSERT(input->IsDoubleRegister());
3308 LOperand* result = instr->result();
3309 ASSERT(result->IsRegister());
3310
3311 XMMRegister input_reg = ToDoubleRegister(input);
3312 Register result_reg = ToRegister(result);
3313
3314 if (instr->truncating()) {
3315 // Performs a truncating conversion of a floating point number as used by
3316 // the JS bitwise operations.
3317 __ cvttsd2si(result_reg, Operand(input_reg));
3318 __ cmp(result_reg, 0x80000000u);
3319 if (CpuFeatures::IsSupported(SSE3)) {
3320 // This will deoptimize if the exponent of the input in out of range.
3321 CpuFeatures::Scope scope(SSE3);
3322 NearLabel convert, done;
3323 __ j(not_equal, &done);
3324 __ sub(Operand(esp), Immediate(kDoubleSize));
3325 __ movdbl(Operand(esp, 0), input_reg);
3326 // Get exponent alone and check for too-big exponent.
3327 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3328 __ and_(result_reg, HeapNumber::kExponentMask);
3329 const uint32_t kTooBigExponent =
3330 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3331 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
3332 __ j(less, &convert);
3333 __ add(Operand(esp), Immediate(kDoubleSize));
3334 DeoptimizeIf(no_condition, instr->environment());
3335 __ bind(&convert);
3336 // Do conversion, which cannot fail because we checked the exponent.
3337 __ fld_d(Operand(esp, 0));
3338 __ fisttp_d(Operand(esp, 0));
3339 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3340 __ add(Operand(esp), Immediate(kDoubleSize));
3341 __ bind(&done);
3342 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003343 NearLabel done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003344 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003345 XMMRegister xmm_scratch = xmm0;
3346
3347 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3348 // manual conversion.
3349 __ j(not_equal, &done);
3350
3351 // Get high 32 bits of the input in result_reg and temp_reg.
3352 __ pshufd(xmm_scratch, input_reg, 1);
3353 __ movd(Operand(temp_reg), xmm_scratch);
3354 __ mov(result_reg, temp_reg);
3355
3356 // Prepare negation mask in temp_reg.
3357 __ sar(temp_reg, kBitsPerInt - 1);
3358
3359 // Extract the exponent from result_reg and subtract adjusted
3360 // bias from it. The adjustment is selected in a way such that
3361 // when the difference is zero, the answer is in the low 32 bits
3362 // of the input, otherwise a shift has to be performed.
3363 __ shr(result_reg, HeapNumber::kExponentShift);
3364 __ and_(result_reg,
3365 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3366 __ sub(Operand(result_reg),
3367 Immediate(HeapNumber::kExponentBias +
3368 HeapNumber::kExponentBits +
3369 HeapNumber::kMantissaBits));
3370 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3371 // special exponents.
3372 DeoptimizeIf(greater, instr->environment());
3373
3374 // Zero out the sign and the exponent in the input (by shifting
3375 // it to the left) and restore the implicit mantissa bit,
3376 // i.e. convert the input to unsigned int64 shifted left by
3377 // kExponentBits.
3378 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3379 // Minus zero has the most significant bit set and the other
3380 // bits cleared.
3381 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3382 __ psllq(input_reg, HeapNumber::kExponentBits);
3383 __ por(input_reg, xmm_scratch);
3384
3385 // Get the amount to shift the input right in xmm_scratch.
3386 __ neg(result_reg);
3387 __ movd(xmm_scratch, Operand(result_reg));
3388
3389 // Shift the input right and extract low 32 bits.
3390 __ psrlq(input_reg, xmm_scratch);
3391 __ movd(Operand(result_reg), input_reg);
3392
3393 // Use the prepared mask in temp_reg to negate the result if necessary.
3394 __ xor_(result_reg, Operand(temp_reg));
3395 __ sub(result_reg, Operand(temp_reg));
3396 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003397 }
3398 } else {
3399 NearLabel done;
3400 __ cvttsd2si(result_reg, Operand(input_reg));
3401 __ cvtsi2sd(xmm0, Operand(result_reg));
3402 __ ucomisd(xmm0, input_reg);
3403 DeoptimizeIf(not_equal, instr->environment());
3404 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3405 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3406 // The integer converted back is equal to the original. We
3407 // only have to test if we got -0 as an input.
3408 __ test(result_reg, Operand(result_reg));
3409 __ j(not_zero, &done);
3410 __ movmskpd(result_reg, input_reg);
3411 // Bit 0 contains the sign of the double in input_reg.
3412 // If input was positive, we are ok and return 0, otherwise
3413 // deoptimize.
3414 __ and_(result_reg, 1);
3415 DeoptimizeIf(not_zero, instr->environment());
3416 }
3417 __ bind(&done);
3418 }
3419}
3420
3421
3422void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003423 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003424 ASSERT(input->IsRegister());
3425 __ test(ToRegister(input), Immediate(kSmiTagMask));
3426 DeoptimizeIf(instr->condition(), instr->environment());
3427}
3428
3429
3430void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003431 Register input = ToRegister(instr->InputAt(0));
3432 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003433 InstanceType first = instr->hydrogen()->first();
3434 InstanceType last = instr->hydrogen()->last();
3435
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003436 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003437
3438 // If there is only one type in the interval check for equality.
3439 if (first == last) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003440 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3441 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003442 DeoptimizeIf(not_equal, instr->environment());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003443 } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
3444 // String has a dedicated bit in instance type.
3445 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), kIsNotStringMask);
3446 DeoptimizeIf(not_zero, instr->environment());
3447 } else {
3448 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3449 static_cast<int8_t>(first));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003450 DeoptimizeIf(below, instr->environment());
3451 // Omit check for the last type.
3452 if (last != LAST_TYPE) {
3453 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3454 static_cast<int8_t>(last));
3455 DeoptimizeIf(above, instr->environment());
3456 }
3457 }
3458}
3459
3460
3461void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003462 ASSERT(instr->InputAt(0)->IsRegister());
3463 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003464 __ cmp(reg, instr->hydrogen()->target());
3465 DeoptimizeIf(not_equal, instr->environment());
3466}
3467
3468
3469void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003470 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003471 ASSERT(input->IsRegister());
3472 Register reg = ToRegister(input);
3473 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3474 instr->hydrogen()->map());
3475 DeoptimizeIf(not_equal, instr->environment());
3476}
3477
3478
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003479void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
3480 if (Heap::InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003481 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003482 Factory::NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003483 __ mov(result, Operand::Cell(cell));
3484 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003485 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003486 }
3487}
3488
3489
3490void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003491 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003492
3493 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003494 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003495
3496 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003497 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003498
3499 // Check prototype maps up to the holder.
3500 while (!current_prototype.is_identical_to(holder)) {
3501 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3502 Handle<Map>(current_prototype->map()));
3503 DeoptimizeIf(not_equal, instr->environment());
3504 current_prototype =
3505 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
3506 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003507 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003508 }
3509
3510 // Check the holder map.
3511 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3512 Handle<Map>(current_prototype->map()));
3513 DeoptimizeIf(not_equal, instr->environment());
3514}
3515
3516
3517void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
3518 // Setup the parameters to the stub/runtime call.
3519 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3520 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3521 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3522 __ push(Immediate(instr->hydrogen()->constant_elements()));
3523
3524 // Pick the right runtime function or stub to call.
3525 int length = instr->hydrogen()->length();
3526 if (instr->hydrogen()->IsCopyOnWrite()) {
3527 ASSERT(instr->hydrogen()->depth() == 1);
3528 FastCloneShallowArrayStub::Mode mode =
3529 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
3530 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003531 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003532 } else if (instr->hydrogen()->depth() > 1) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003533 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003534 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003535 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003536 } else {
3537 FastCloneShallowArrayStub::Mode mode =
3538 FastCloneShallowArrayStub::CLONE_ELEMENTS;
3539 FastCloneShallowArrayStub stub(mode, length);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003540 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003541 }
3542}
3543
3544
3545void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003546 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003547 // Setup the parameters to the stub/runtime call.
3548 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3549 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
3550 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3551 __ push(Immediate(instr->hydrogen()->constant_properties()));
3552 __ push(Immediate(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
3553
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003554 // Pick the right runtime function to call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003555 if (instr->hydrogen()->depth() > 1) {
3556 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
3557 } else {
3558 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
3559 }
3560}
3561
3562
3563void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
3564 NearLabel materialized;
3565 // Registers will be used as follows:
3566 // edi = JS function.
3567 // ecx = literals array.
3568 // ebx = regexp literal.
3569 // eax = regexp literal clone.
3570 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3571 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
3572 int literal_offset = FixedArray::kHeaderSize +
3573 instr->hydrogen()->literal_index() * kPointerSize;
3574 __ mov(ebx, FieldOperand(ecx, literal_offset));
3575 __ cmp(ebx, Factory::undefined_value());
3576 __ j(not_equal, &materialized);
3577
3578 // Create regexp literal using runtime function
3579 // Result will be in eax.
3580 __ push(ecx);
3581 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
3582 __ push(Immediate(instr->hydrogen()->pattern()));
3583 __ push(Immediate(instr->hydrogen()->flags()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003584 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003585 __ mov(ebx, eax);
3586
3587 __ bind(&materialized);
3588 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
3589 Label allocated, runtime_allocate;
3590 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
3591 __ jmp(&allocated);
3592
3593 __ bind(&runtime_allocate);
3594 __ push(ebx);
3595 __ push(Immediate(Smi::FromInt(size)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003596 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003597 __ pop(ebx);
3598
3599 __ bind(&allocated);
3600 // Copy the content into the newly allocated memory.
3601 // (Unroll copy loop once for better throughput).
3602 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
3603 __ mov(edx, FieldOperand(ebx, i));
3604 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
3605 __ mov(FieldOperand(eax, i), edx);
3606 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
3607 }
3608 if ((size % (2 * kPointerSize)) != 0) {
3609 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
3610 __ mov(FieldOperand(eax, size - kPointerSize), edx);
3611 }
3612}
3613
3614
3615void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
3616 // Use the fast case closure allocation code that allocates in new
3617 // space for nested functions that don't need literals cloning.
3618 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003619 bool pretenure = instr->hydrogen()->pretenure();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003620 if (shared_info->num_literals() == 0 && !pretenure) {
3621 FastNewClosureStub stub;
3622 __ push(Immediate(shared_info));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003623 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003624 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003625 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003626 __ push(Immediate(shared_info));
3627 __ push(Immediate(pretenure
3628 ? Factory::true_value()
3629 : Factory::false_value()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003630 CallRuntime(Runtime::kNewClosure, 3, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003631 }
3632}
3633
3634
3635void LCodeGen::DoTypeof(LTypeof* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003636 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003637 if (input->IsConstantOperand()) {
3638 __ push(ToImmediate(input));
3639 } else {
3640 __ push(ToOperand(input));
3641 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003642 CallRuntime(Runtime::kTypeof, 1, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003643}
3644
3645
3646void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003647 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003648 Register result = ToRegister(instr->result());
3649 Label true_label;
3650 Label false_label;
3651 NearLabel done;
3652
3653 Condition final_branch_condition = EmitTypeofIs(&true_label,
3654 &false_label,
3655 input,
3656 instr->type_literal());
3657 __ j(final_branch_condition, &true_label);
3658 __ bind(&false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003659 __ mov(result, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003660 __ jmp(&done);
3661
3662 __ bind(&true_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003663 __ mov(result, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003664
3665 __ bind(&done);
3666}
3667
3668
3669void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003670 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003671 int true_block = chunk_->LookupDestination(instr->true_block_id());
3672 int false_block = chunk_->LookupDestination(instr->false_block_id());
3673 Label* true_label = chunk_->GetAssemblyLabel(true_block);
3674 Label* false_label = chunk_->GetAssemblyLabel(false_block);
3675
3676 Condition final_branch_condition = EmitTypeofIs(true_label,
3677 false_label,
3678 input,
3679 instr->type_literal());
3680
3681 EmitBranch(true_block, false_block, final_branch_condition);
3682}
3683
3684
3685Condition LCodeGen::EmitTypeofIs(Label* true_label,
3686 Label* false_label,
3687 Register input,
3688 Handle<String> type_name) {
3689 Condition final_branch_condition = no_condition;
3690 if (type_name->Equals(Heap::number_symbol())) {
3691 __ test(input, Immediate(kSmiTagMask));
3692 __ j(zero, true_label);
3693 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
3694 Factory::heap_number_map());
3695 final_branch_condition = equal;
3696
3697 } else if (type_name->Equals(Heap::string_symbol())) {
3698 __ test(input, Immediate(kSmiTagMask));
3699 __ j(zero, false_label);
3700 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
3701 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3702 1 << Map::kIsUndetectable);
3703 __ j(not_zero, false_label);
3704 __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
3705 final_branch_condition = below;
3706
3707 } else if (type_name->Equals(Heap::boolean_symbol())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003708 __ cmp(input, Factory::true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003709 __ j(equal, true_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003710 __ cmp(input, Factory::false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003711 final_branch_condition = equal;
3712
3713 } else if (type_name->Equals(Heap::undefined_symbol())) {
3714 __ cmp(input, Factory::undefined_value());
3715 __ j(equal, true_label);
3716 __ test(input, Immediate(kSmiTagMask));
3717 __ j(zero, false_label);
3718 // Check for undetectable objects => true.
3719 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
3720 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3721 1 << Map::kIsUndetectable);
3722 final_branch_condition = not_zero;
3723
3724 } else if (type_name->Equals(Heap::function_symbol())) {
3725 __ test(input, Immediate(kSmiTagMask));
3726 __ j(zero, false_label);
3727 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
3728 __ j(equal, true_label);
3729 // Regular expressions => 'function' (they are callable).
3730 __ CmpInstanceType(input, JS_REGEXP_TYPE);
3731 final_branch_condition = equal;
3732
3733 } else if (type_name->Equals(Heap::object_symbol())) {
3734 __ test(input, Immediate(kSmiTagMask));
3735 __ j(zero, false_label);
3736 __ cmp(input, Factory::null_value());
3737 __ j(equal, true_label);
3738 // Regular expressions => 'function', not 'object'.
3739 __ CmpObjectType(input, JS_REGEXP_TYPE, input);
3740 __ j(equal, false_label);
3741 // Check for undetectable objects => false.
3742 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
3743 1 << Map::kIsUndetectable);
3744 __ j(not_zero, false_label);
3745 // Check for JS objects => true.
3746 __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
3747 __ j(below, false_label);
3748 __ CmpInstanceType(input, LAST_JS_OBJECT_TYPE);
3749 final_branch_condition = below_equal;
3750
3751 } else {
3752 final_branch_condition = not_equal;
3753 __ jmp(false_label);
3754 // A dead branch instruction will be generated after this point.
3755 }
3756
3757 return final_branch_condition;
3758}
3759
3760
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003761void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
3762 Register result = ToRegister(instr->result());
3763 NearLabel true_label;
3764 NearLabel false_label;
3765 NearLabel done;
3766
3767 EmitIsConstructCall(result);
3768 __ j(equal, &true_label);
3769
3770 __ mov(result, Factory::false_value());
3771 __ jmp(&done);
3772
3773 __ bind(&true_label);
3774 __ mov(result, Factory::true_value());
3775
3776 __ bind(&done);
3777}
3778
3779
3780void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
3781 Register temp = ToRegister(instr->TempAt(0));
3782 int true_block = chunk_->LookupDestination(instr->true_block_id());
3783 int false_block = chunk_->LookupDestination(instr->false_block_id());
3784
3785 EmitIsConstructCall(temp);
3786 EmitBranch(true_block, false_block, equal);
3787}
3788
3789
3790void LCodeGen::EmitIsConstructCall(Register temp) {
3791 // Get the frame pointer for the calling frame.
3792 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3793
3794 // Skip the arguments adaptor frame if it exists.
3795 NearLabel check_frame_marker;
3796 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
3797 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3798 __ j(not_equal, &check_frame_marker);
3799 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
3800
3801 // Check the marker in the calling frame.
3802 __ bind(&check_frame_marker);
3803 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
3804 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
3805}
3806
3807
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003808void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
3809 // No code for lazy bailout instruction. Used to capture environment after a
3810 // call for populating the safepoint data with deoptimization data.
3811}
3812
3813
3814void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
3815 DeoptimizeIf(no_condition, instr->environment());
3816}
3817
3818
3819void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
3820 LOperand* obj = instr->object();
3821 LOperand* key = instr->key();
3822 __ push(ToOperand(obj));
3823 if (key->IsConstantOperand()) {
3824 __ push(ToImmediate(key));
3825 } else {
3826 __ push(ToOperand(key));
3827 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003828 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
3829 LPointerMap* pointers = instr->pointer_map();
3830 LEnvironment* env = instr->deoptimization_environment();
3831 RecordPosition(pointers->position());
3832 RegisterEnvironmentForDeoptimization(env);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003833 // Create safepoint generator that will also ensure enough space in the
3834 // reloc info for patching in deoptimization (since this is invoking a
3835 // builtin)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003836 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003837 pointers,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003838 env->deoptimization_index(),
3839 true);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003840 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003841 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003842 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
3843}
3844
3845
3846void LCodeGen::DoStackCheck(LStackCheck* instr) {
3847 // Perform stack overflow check.
3848 NearLabel done;
3849 ExternalReference stack_limit = ExternalReference::address_of_stack_limit();
3850 __ cmp(esp, Operand::StaticVariable(stack_limit));
3851 __ j(above_equal, &done);
3852
3853 StackCheckStub stub;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003854 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003855 __ bind(&done);
3856}
3857
3858
3859void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
3860 // This is a pseudo-instruction that ensures that the environment here is
3861 // properly registered for deoptimization and records the assembler's PC
3862 // offset.
3863 LEnvironment* environment = instr->environment();
3864 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
3865 instr->SpilledDoubleRegisterArray());
3866
3867 // If the environment were already registered, we would have no way of
3868 // backpatching it with the spill slot operands.
3869 ASSERT(!environment->HasBeenRegistered());
3870 RegisterEnvironmentForDeoptimization(environment);
3871 ASSERT(osr_pc_offset_ == -1);
3872 osr_pc_offset_ = masm()->pc_offset();
3873}
3874
3875
3876#undef __
3877
3878} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003879
3880#endif // V8_TARGET_ARCH_IA32