blob: 5a0b0f39fa32c4307bc03747b4de8c0d166af508 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
33#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000034#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
40
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000041// When invoking builtins, we need to record the safepoint in the middle of
42// the invoke instruction sequence generated by the macro assembler.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000043class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000044 public:
45 SafepointGenerator(LCodeGen* codegen,
46 LPointerMap* pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000047 int deoptimization_index)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048 : codegen_(codegen),
49 pointers_(pointers),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000050 deoptimization_index_(deoptimization_index) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051 virtual ~SafepointGenerator() { }
52
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053 virtual void BeforeCall(int call_size) const {}
54
55 virtual void AfterCall() const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000056 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
57 }
58
59 private:
60 LCodeGen* codegen_;
61 LPointerMap* pointers_;
62 int deoptimization_index_;
63};
64
65
66#define __ masm()->
67
68bool LCodeGen::GenerateCode() {
69 HPhase phase("Code generation", chunk());
70 ASSERT(is_unused());
71 status_ = GENERATING;
72 CpuFeatures::Scope scope(SSE2);
73 return GeneratePrologue() &&
74 GenerateBody() &&
75 GenerateDeferredCode() &&
76 GenerateSafepointTable();
77}
78
79
80void LCodeGen::FinishCode(Handle<Code> code) {
81 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000082 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000083 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000084 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000085 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000086}
87
88
89void LCodeGen::Abort(const char* format, ...) {
90 if (FLAG_trace_bailout) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000091 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
92 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000093 va_list arguments;
94 va_start(arguments, format);
95 OS::VPrint(format, arguments);
96 va_end(arguments);
97 PrintF("\n");
98 }
99 status_ = ABORTED;
100}
101
102
103void LCodeGen::Comment(const char* format, ...) {
104 if (!FLAG_code_comments) return;
105 char buffer[4 * KB];
106 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
107 va_list arguments;
108 va_start(arguments, format);
109 builder.AddFormattedList(format, arguments);
110 va_end(arguments);
111
112 // Copy the string before recording it in the assembler to avoid
113 // issues when the stack allocated buffer goes out of scope.
114 size_t length = builder.position();
115 Vector<char> copy = Vector<char>::New(length + 1);
116 memcpy(copy.start(), builder.Finalize(), copy.length());
117 masm()->RecordComment(copy.start());
118}
119
120
121bool LCodeGen::GeneratePrologue() {
122 ASSERT(is_generating());
123
124#ifdef DEBUG
125 if (strlen(FLAG_stop_at) > 0 &&
126 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
127 __ int3();
128 }
129#endif
130
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000131 // Strict mode functions and builtins need to replace the receiver
132 // with undefined when called as functions (without an explicit
133 // receiver object). ecx is zero for method calls and non-zero for
134 // function calls.
135 if (info_->is_strict_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000136 Label ok;
137 __ test(ecx, Operand(ecx));
138 __ j(zero, &ok, Label::kNear);
139 // +1 for return address.
140 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
141 __ mov(Operand(esp, receiver_offset),
142 Immediate(isolate()->factory()->undefined_value()));
143 __ bind(&ok);
144 }
145
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000146 __ 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.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000152 int slots = GetStackSlotCount();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000153 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());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000274 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000275 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000388void LCodeGen::AddToTranslation(Translation* translation,
389 LOperand* op,
390 bool is_tagged) {
391 if (op == NULL) {
392 // TODO(twuerthinger): Introduce marker operands to indicate that this value
393 // is not present and must be reconstructed from the deoptimizer. Currently
394 // this is only used for the arguments object.
395 translation->StoreArgumentsObject();
396 } else if (op->IsStackSlot()) {
397 if (is_tagged) {
398 translation->StoreStackSlot(op->index());
399 } else {
400 translation->StoreInt32StackSlot(op->index());
401 }
402 } else if (op->IsDoubleStackSlot()) {
403 translation->StoreDoubleStackSlot(op->index());
404 } else if (op->IsArgument()) {
405 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000406 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000407 translation->StoreStackSlot(src_index);
408 } else if (op->IsRegister()) {
409 Register reg = ToRegister(op);
410 if (is_tagged) {
411 translation->StoreRegister(reg);
412 } else {
413 translation->StoreInt32Register(reg);
414 }
415 } else if (op->IsDoubleRegister()) {
416 XMMRegister reg = ToDoubleRegister(op);
417 translation->StoreDoubleRegister(reg);
418 } else if (op->IsConstantOperand()) {
419 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
420 int src_index = DefineDeoptimizationLiteral(literal);
421 translation->StoreLiteral(src_index);
422 } else {
423 UNREACHABLE();
424 }
425}
426
427
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000428void LCodeGen::CallCodeGeneric(Handle<Code> code,
429 RelocInfo::Mode mode,
430 LInstruction* instr,
431 ContextMode context_mode,
432 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000433 ASSERT(instr != NULL);
434 LPointerMap* pointers = instr->pointer_map();
435 RecordPosition(pointers->position());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000436
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000437 if (context_mode == RESTORE_CONTEXT) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000438 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
439 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000440 __ call(code, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000441
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000442 RegisterLazyDeoptimization(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000443
444 // Signal that we don't inline smi code before these stubs in the
445 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000446 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000447 code->kind() == Code::COMPARE_IC) {
448 __ nop();
449 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000450}
451
452
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000453void LCodeGen::CallCode(Handle<Code> code,
454 RelocInfo::Mode mode,
455 LInstruction* instr,
456 ContextMode context_mode) {
457 CallCodeGeneric(code, mode, instr, context_mode, RECORD_SIMPLE_SAFEPOINT);
458}
459
460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000462 int argc,
463 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000464 ContextMode context_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000465 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000466 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000468 RecordPosition(pointers->position());
469
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000470 if (context_mode == RESTORE_CONTEXT) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000471 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
472 }
473 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000474
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000475 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000476}
477
478
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000479void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
480 int argc,
481 LInstruction* instr) {
482 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
483 __ CallRuntimeSaveDoubles(id);
484 RecordSafepointWithRegisters(
485 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
486}
487
488
489void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
490 SafepointMode safepoint_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491 // Create the environment to bailout to. If the call has side effects
492 // execution has to continue after the call otherwise execution can continue
493 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000494 LEnvironment* deoptimization_environment;
495 if (instr->HasDeoptimizationEnvironment()) {
496 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000497 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000498 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000499 }
500
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000501 RegisterEnvironmentForDeoptimization(deoptimization_environment);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000502 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
503 RecordSafepoint(instr->pointer_map(),
504 deoptimization_environment->deoptimization_index());
505 } else {
506 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
507 RecordSafepointWithRegisters(
508 instr->pointer_map(),
509 0,
510 deoptimization_environment->deoptimization_index());
511 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000512}
513
514
515void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
516 if (!environment->HasBeenRegistered()) {
517 // Physical stack frame layout:
518 // -x ............. -4 0 ..................................... y
519 // [incoming arguments] [spill slots] [pushed outgoing arguments]
520
521 // Layout of the environment:
522 // 0 ..................................................... size-1
523 // [parameters] [locals] [expression stack including arguments]
524
525 // Layout of the translation:
526 // 0 ........................................................ size - 1 + 4
527 // [expression stack including arguments] [locals] [4 words] [parameters]
528 // |>------------ translation_size ------------<|
529
530 int frame_count = 0;
531 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
532 ++frame_count;
533 }
534 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000535 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000536 int deoptimization_index = deoptimizations_.length();
537 environment->Register(deoptimization_index, translation.index());
538 deoptimizations_.Add(environment);
539 }
540}
541
542
543void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
544 RegisterEnvironmentForDeoptimization(environment);
545 ASSERT(environment->HasBeenRegistered());
546 int id = environment->deoptimization_index();
547 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
548 ASSERT(entry != NULL);
549 if (entry == NULL) {
550 Abort("bailout was not prepared");
551 return;
552 }
553
554 if (FLAG_deopt_every_n_times != 0) {
555 Handle<SharedFunctionInfo> shared(info_->shared_info());
556 Label no_deopt;
557 __ pushfd();
558 __ push(eax);
559 __ push(ebx);
560 __ mov(ebx, shared);
561 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
562 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000563 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000564 if (FLAG_trap_on_deopt) __ int3();
565 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
566 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
567 __ pop(ebx);
568 __ pop(eax);
569 __ popfd();
570 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
571
572 __ bind(&no_deopt);
573 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
574 __ pop(ebx);
575 __ pop(eax);
576 __ popfd();
577 }
578
579 if (cc == no_condition) {
580 if (FLAG_trap_on_deopt) __ int3();
581 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
582 } else {
583 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000584 Label done;
585 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000586 __ int3();
587 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
588 __ bind(&done);
589 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000590 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000591 }
592 }
593}
594
595
596void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
597 int length = deoptimizations_.length();
598 if (length == 0) return;
599 ASSERT(FLAG_deopt);
600 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000603 Handle<ByteArray> translations = translations_.CreateByteArray();
604 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000605 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
606
607 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 for (int i = 0; i < deoptimization_literals_.length(); i++) {
610 literals->set(i, *deoptimization_literals_[i]);
611 }
612 data->SetLiteralArray(*literals);
613
614 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
615 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
616
617 // Populate the deoptimization entries.
618 for (int i = 0; i < length; i++) {
619 LEnvironment* env = deoptimizations_[i];
620 data->SetAstId(i, Smi::FromInt(env->ast_id()));
621 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
622 data->SetArgumentsStackHeight(i,
623 Smi::FromInt(env->arguments_stack_height()));
624 }
625 code->set_deoptimization_data(*data);
626}
627
628
629int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
630 int result = deoptimization_literals_.length();
631 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
632 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
633 }
634 deoptimization_literals_.Add(literal);
635 return result;
636}
637
638
639void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
640 ASSERT(deoptimization_literals_.length() == 0);
641
642 const ZoneList<Handle<JSFunction> >* inlined_closures =
643 chunk()->inlined_closures();
644
645 for (int i = 0, length = inlined_closures->length();
646 i < length;
647 i++) {
648 DefineDeoptimizationLiteral(inlined_closures->at(i));
649 }
650
651 inlined_function_count_ = deoptimization_literals_.length();
652}
653
654
ager@chromium.org378b34e2011-01-28 08:04:38 +0000655void LCodeGen::RecordSafepoint(
656 LPointerMap* pointers,
657 Safepoint::Kind kind,
658 int arguments,
659 int deoptimization_index) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000660 ASSERT(kind == expected_safepoint_kind_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000661 const ZoneList<LOperand*>* operands = pointers->operands();
662 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000663 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664 for (int i = 0; i < operands->length(); i++) {
665 LOperand* pointer = operands->at(i);
666 if (pointer->IsStackSlot()) {
667 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000668 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
669 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670 }
671 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000672}
673
674
675void LCodeGen::RecordSafepoint(LPointerMap* pointers,
676 int deoptimization_index) {
677 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678}
679
680
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000681void LCodeGen::RecordSafepoint(int deoptimization_index) {
682 LPointerMap empty_pointers(RelocInfo::kNoPosition);
683 RecordSafepoint(&empty_pointers, deoptimization_index);
684}
685
686
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000687void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
688 int arguments,
689 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000690 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
691 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000692}
693
694
695void LCodeGen::RecordPosition(int position) {
696 if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
697 masm()->positions_recorder()->RecordPosition(position);
698}
699
700
701void LCodeGen::DoLabel(LLabel* label) {
702 if (label->is_loop_header()) {
703 Comment(";;; B%d - LOOP entry", label->block_id());
704 } else {
705 Comment(";;; B%d", label->block_id());
706 }
707 __ bind(label->label());
708 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000709 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000710}
711
712
713void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000714 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000715}
716
717
718void LCodeGen::DoGap(LGap* gap) {
719 for (int i = LGap::FIRST_INNER_POSITION;
720 i <= LGap::LAST_INNER_POSITION;
721 i++) {
722 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
723 LParallelMove* move = gap->GetParallelMove(inner_pos);
724 if (move != NULL) DoParallelMove(move);
725 }
726
727 LInstruction* next = GetNextInstruction();
728 if (next != NULL && next->IsLazyBailout()) {
729 int pc = masm()->pc_offset();
730 safepoints_.SetPcAfterGap(pc);
731 }
732}
733
734
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000735void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
736 DoGap(instr);
737}
738
739
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000740void LCodeGen::DoParameter(LParameter* instr) {
741 // Nothing to do.
742}
743
744
745void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000746 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000747 ASSERT(ToRegister(instr->result()).is(eax));
748 switch (instr->hydrogen()->major_key()) {
749 case CodeStub::RegExpConstructResult: {
750 RegExpConstructResultStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000751 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000752 break;
753 }
754 case CodeStub::RegExpExec: {
755 RegExpExecStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000756 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000757 break;
758 }
759 case CodeStub::SubString: {
760 SubStringStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000761 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000762 break;
763 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000764 case CodeStub::NumberToString: {
765 NumberToStringStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000766 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000767 break;
768 }
769 case CodeStub::StringAdd: {
770 StringAddStub stub(NO_STRING_ADD_FLAGS);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000771 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000772 break;
773 }
774 case CodeStub::StringCompare: {
775 StringCompareStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000776 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000777 break;
778 }
779 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000780 TranscendentalCacheStub stub(instr->transcendental_type(),
781 TranscendentalCacheStub::TAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000782 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000783 break;
784 }
785 default:
786 UNREACHABLE();
787 }
788}
789
790
791void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
792 // Nothing to do.
793}
794
795
796void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000797 if (instr->hydrogen()->HasPowerOf2Divisor()) {
798 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000799
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000800 int32_t divisor =
801 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000802
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000803 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000804
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000805 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000806 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000807 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000808 __ neg(dividend);
809 __ and_(dividend, divisor - 1);
810 __ neg(dividend);
811 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000812 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000813 DeoptimizeIf(no_condition, instr->environment());
814 }
815 __ bind(&positive_dividend);
816 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817 __ bind(&done);
818 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000819 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000820 Register left_reg = ToRegister(instr->InputAt(0));
821 Register right_reg = ToRegister(instr->InputAt(1));
822 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000823
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000824 ASSERT(left_reg.is(eax));
825 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000826 ASSERT(!right_reg.is(eax));
827 ASSERT(!right_reg.is(edx));
828
829 // Check for x % 0.
830 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000831 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000832 DeoptimizeIf(zero, instr->environment());
833 }
834
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000835 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000836 __ j(zero, &remainder_eq_dividend, Label::kNear);
837 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000838
839 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000840 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000841 // The sign of the divisor doesn't matter.
842 __ neg(right_reg);
843
844 __ bind(&both_positive);
845 // If the dividend is smaller than the nonnegative
846 // divisor, the dividend is the result.
847 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000848 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000849
850 // Check if the divisor is a PowerOfTwo integer.
851 Register scratch = ToRegister(instr->TempAt(0));
852 __ mov(scratch, right_reg);
853 __ sub(Operand(scratch), Immediate(1));
854 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000855 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000856 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000857 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000858
859 __ bind(&do_subtraction);
860 const int kUnfolds = 3;
861 // Try a few subtractions of the dividend.
862 __ mov(scratch, left_reg);
863 for (int i = 0; i < kUnfolds; i++) {
864 // Reduce the dividend by the divisor.
865 __ sub(left_reg, Operand(right_reg));
866 // Check if the dividend is less than the divisor.
867 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000868 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000869 }
870 __ mov(left_reg, scratch);
871
872 // Slow case, using idiv instruction.
873 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000874 // Sign extend to edx.
875 __ cdq();
876
877 // Check for (0 % -x) that will produce negative zero.
878 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000879 Label positive_left;
880 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000881 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000882 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000883 __ idiv(right_reg);
884
885 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000886 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000887 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000888
889 DeoptimizeIf(no_condition, instr->environment());
890 __ bind(&positive_left);
891 __ idiv(right_reg);
892 __ bind(&done);
893 } else {
894 __ idiv(right_reg);
895 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000896 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000897
898 __ bind(&remainder_eq_dividend);
899 __ mov(result_reg, left_reg);
900
901 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000902 }
903}
904
905
906void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000907 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000908 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000909 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
910 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
911 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000912
913 Register left_reg = eax;
914
915 // Check for x / 0.
916 Register right_reg = ToRegister(right);
917 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
918 __ test(right_reg, ToOperand(right));
919 DeoptimizeIf(zero, instr->environment());
920 }
921
922 // Check for (0 / -x) that will produce negative zero.
923 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000924 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000925 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000926 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927 __ test(right_reg, ToOperand(right));
928 DeoptimizeIf(sign, instr->environment());
929 __ bind(&left_not_zero);
930 }
931
932 // Check for (-kMinInt / -1).
933 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000934 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000935 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000936 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000937 __ cmp(right_reg, -1);
938 DeoptimizeIf(zero, instr->environment());
939 __ bind(&left_not_min_int);
940 }
941
942 // Sign extend to edx.
943 __ cdq();
944 __ idiv(right_reg);
945
946 // Deoptimize if remainder is not 0.
947 __ test(edx, Operand(edx));
948 DeoptimizeIf(not_zero, instr->environment());
949}
950
951
952void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000953 Register left = ToRegister(instr->InputAt(0));
954 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000955
956 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000957 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000958 }
959
960 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000961 // Try strength reductions on the multiplication.
962 // All replacement instructions are at most as long as the imul
963 // and have better latency.
964 int constant = ToInteger32(LConstantOperand::cast(right));
965 if (constant == -1) {
966 __ neg(left);
967 } else if (constant == 0) {
968 __ xor_(left, Operand(left));
969 } else if (constant == 2) {
970 __ add(left, Operand(left));
971 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
972 // If we know that the multiplication can't overflow, it's safe to
973 // use instructions that don't set the overflow flag for the
974 // multiplication.
975 switch (constant) {
976 case 1:
977 // Do nothing.
978 break;
979 case 3:
980 __ lea(left, Operand(left, left, times_2, 0));
981 break;
982 case 4:
983 __ shl(left, 2);
984 break;
985 case 5:
986 __ lea(left, Operand(left, left, times_4, 0));
987 break;
988 case 8:
989 __ shl(left, 3);
990 break;
991 case 9:
992 __ lea(left, Operand(left, left, times_8, 0));
993 break;
994 case 16:
995 __ shl(left, 4);
996 break;
997 default:
998 __ imul(left, left, constant);
999 break;
1000 }
1001 } else {
1002 __ imul(left, left, constant);
1003 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001004 } else {
1005 __ imul(left, ToOperand(right));
1006 }
1007
1008 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1009 DeoptimizeIf(overflow, instr->environment());
1010 }
1011
1012 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1013 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001014 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001015 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001016 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001017 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001018 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 DeoptimizeIf(no_condition, instr->environment());
1020 }
1021 } else {
1022 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001023 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 DeoptimizeIf(sign, instr->environment());
1025 }
1026 __ bind(&done);
1027 }
1028}
1029
1030
1031void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001032 LOperand* left = instr->InputAt(0);
1033 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001034 ASSERT(left->Equals(instr->result()));
1035 ASSERT(left->IsRegister());
1036
1037 if (right->IsConstantOperand()) {
1038 int right_operand = ToInteger32(LConstantOperand::cast(right));
1039 switch (instr->op()) {
1040 case Token::BIT_AND:
1041 __ and_(ToRegister(left), right_operand);
1042 break;
1043 case Token::BIT_OR:
1044 __ or_(ToRegister(left), right_operand);
1045 break;
1046 case Token::BIT_XOR:
1047 __ xor_(ToRegister(left), right_operand);
1048 break;
1049 default:
1050 UNREACHABLE();
1051 break;
1052 }
1053 } else {
1054 switch (instr->op()) {
1055 case Token::BIT_AND:
1056 __ and_(ToRegister(left), ToOperand(right));
1057 break;
1058 case Token::BIT_OR:
1059 __ or_(ToRegister(left), ToOperand(right));
1060 break;
1061 case Token::BIT_XOR:
1062 __ xor_(ToRegister(left), ToOperand(right));
1063 break;
1064 default:
1065 UNREACHABLE();
1066 break;
1067 }
1068 }
1069}
1070
1071
1072void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001073 LOperand* left = instr->InputAt(0);
1074 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075 ASSERT(left->Equals(instr->result()));
1076 ASSERT(left->IsRegister());
1077 if (right->IsRegister()) {
1078 ASSERT(ToRegister(right).is(ecx));
1079
1080 switch (instr->op()) {
1081 case Token::SAR:
1082 __ sar_cl(ToRegister(left));
1083 break;
1084 case Token::SHR:
1085 __ shr_cl(ToRegister(left));
1086 if (instr->can_deopt()) {
1087 __ test(ToRegister(left), Immediate(0x80000000));
1088 DeoptimizeIf(not_zero, instr->environment());
1089 }
1090 break;
1091 case Token::SHL:
1092 __ shl_cl(ToRegister(left));
1093 break;
1094 default:
1095 UNREACHABLE();
1096 break;
1097 }
1098 } else {
1099 int value = ToInteger32(LConstantOperand::cast(right));
1100 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1101 switch (instr->op()) {
1102 case Token::SAR:
1103 if (shift_count != 0) {
1104 __ sar(ToRegister(left), shift_count);
1105 }
1106 break;
1107 case Token::SHR:
1108 if (shift_count == 0 && instr->can_deopt()) {
1109 __ test(ToRegister(left), Immediate(0x80000000));
1110 DeoptimizeIf(not_zero, instr->environment());
1111 } else {
1112 __ shr(ToRegister(left), shift_count);
1113 }
1114 break;
1115 case Token::SHL:
1116 if (shift_count != 0) {
1117 __ shl(ToRegister(left), shift_count);
1118 }
1119 break;
1120 default:
1121 UNREACHABLE();
1122 break;
1123 }
1124 }
1125}
1126
1127
1128void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001129 LOperand* left = instr->InputAt(0);
1130 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001131 ASSERT(left->Equals(instr->result()));
1132
1133 if (right->IsConstantOperand()) {
1134 __ sub(ToOperand(left), ToImmediate(right));
1135 } else {
1136 __ sub(ToRegister(left), ToOperand(right));
1137 }
1138 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1139 DeoptimizeIf(overflow, instr->environment());
1140 }
1141}
1142
1143
1144void LCodeGen::DoConstantI(LConstantI* instr) {
1145 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001146 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001147}
1148
1149
1150void LCodeGen::DoConstantD(LConstantD* instr) {
1151 ASSERT(instr->result()->IsDoubleRegister());
1152 XMMRegister res = ToDoubleRegister(instr->result());
1153 double v = instr->value();
1154 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1155 // do so if the constant is -0.0.
1156 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001157 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001158 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001159 Register temp = ToRegister(instr->TempAt(0));
1160 uint64_t int_val = BitCast<uint64_t, double>(v);
1161 int32_t lower = static_cast<int32_t>(int_val);
1162 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001164 CpuFeatures::Scope scope(SSE4_1);
1165 if (lower != 0) {
1166 __ Set(temp, Immediate(lower));
1167 __ movd(res, Operand(temp));
1168 __ Set(temp, Immediate(upper));
1169 __ pinsrd(res, Operand(temp), 1);
1170 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001171 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001172 __ Set(temp, Immediate(upper));
1173 __ pinsrd(res, Operand(temp), 1);
1174 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001175 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001176 __ Set(temp, Immediate(upper));
1177 __ movd(res, Operand(temp));
1178 __ psllq(res, 32);
1179 if (lower != 0) {
1180 __ Set(temp, Immediate(lower));
1181 __ movd(xmm0, Operand(temp));
1182 __ por(res, xmm0);
1183 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184 }
1185 }
1186}
1187
1188
1189void LCodeGen::DoConstantT(LConstantT* instr) {
1190 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001191 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001192}
1193
1194
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001195void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001196 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001197 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001198 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1199}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001200
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001201
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001202void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
1203 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001204 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001205 __ mov(result, FieldOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001206}
1207
1208
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001209void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001210 Register result = ToRegister(instr->result());
1211 Register array = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001212 __ mov(result, FieldOperand(array, ExternalArray::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001213}
1214
1215
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001216void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001217 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001218 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001219 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001220 ASSERT(input.is(result));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001221 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001222 // If the object is a smi return the object.
1223 __ test(input, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001224 __ j(zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001225
1226 // If the object is not a value type, return the object.
1227 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001228 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001229 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1230
1231 __ bind(&done);
1232}
1233
1234
1235void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001236 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001237 ASSERT(input->Equals(instr->result()));
1238 __ not_(ToRegister(input));
1239}
1240
1241
1242void LCodeGen::DoThrow(LThrow* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001243 __ push(ToOperand(instr->InputAt(0)));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001244 CallRuntime(Runtime::kThrow, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001245
1246 if (FLAG_debug_code) {
1247 Comment("Unreachable code.");
1248 __ int3();
1249 }
1250}
1251
1252
1253void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001254 LOperand* left = instr->InputAt(0);
1255 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001256 ASSERT(left->Equals(instr->result()));
1257
1258 if (right->IsConstantOperand()) {
1259 __ add(ToOperand(left), ToImmediate(right));
1260 } else {
1261 __ add(ToRegister(left), ToOperand(right));
1262 }
1263
1264 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1265 DeoptimizeIf(overflow, instr->environment());
1266 }
1267}
1268
1269
1270void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001271 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1272 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1273 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001275 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001276 switch (instr->op()) {
1277 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001278 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001279 break;
1280 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001281 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001282 break;
1283 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001284 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001285 break;
1286 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001287 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001288 break;
1289 case Token::MOD: {
1290 // Pass two doubles as arguments on the stack.
1291 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001292 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1293 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001294 __ CallCFunction(
1295 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1296 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001297
1298 // Return value is in st(0) on ia32.
1299 // Store it into the (fixed) result register.
1300 __ sub(Operand(esp), Immediate(kDoubleSize));
1301 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001302 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001303 __ add(Operand(esp), Immediate(kDoubleSize));
1304 break;
1305 }
1306 default:
1307 UNREACHABLE();
1308 break;
1309 }
1310}
1311
1312
1313void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001314 ASSERT(ToRegister(instr->InputAt(0)).is(edx));
1315 ASSERT(ToRegister(instr->InputAt(1)).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001316 ASSERT(ToRegister(instr->result()).is(eax));
1317
danno@chromium.org40cb8782011-05-25 07:58:50 +00001318 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001319 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001320}
1321
1322
1323int LCodeGen::GetNextEmittedBlock(int block) {
1324 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1325 LLabel* label = chunk_->GetLabel(i);
1326 if (!label->HasReplacement()) return i;
1327 }
1328 return -1;
1329}
1330
1331
1332void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1333 int next_block = GetNextEmittedBlock(current_block_);
1334 right_block = chunk_->LookupDestination(right_block);
1335 left_block = chunk_->LookupDestination(left_block);
1336
1337 if (right_block == left_block) {
1338 EmitGoto(left_block);
1339 } else if (left_block == next_block) {
1340 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1341 } else if (right_block == next_block) {
1342 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1343 } else {
1344 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1345 __ jmp(chunk_->GetAssemblyLabel(right_block));
1346 }
1347}
1348
1349
1350void LCodeGen::DoBranch(LBranch* instr) {
1351 int true_block = chunk_->LookupDestination(instr->true_block_id());
1352 int false_block = chunk_->LookupDestination(instr->false_block_id());
1353
1354 Representation r = instr->hydrogen()->representation();
1355 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001356 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001357 __ test(reg, Operand(reg));
1358 EmitBranch(true_block, false_block, not_zero);
1359 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001360 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001361 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001362 __ ucomisd(reg, xmm0);
1363 EmitBranch(true_block, false_block, not_equal);
1364 } else {
1365 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001366 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001367 if (instr->hydrogen()->type().IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001369 EmitBranch(true_block, false_block, equal);
1370 } else {
1371 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1372 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001375 __ j(equal, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001377 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 __ cmp(reg, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001379 __ j(equal, false_label);
1380 __ test(reg, Operand(reg));
1381 __ j(equal, false_label);
1382 __ test(reg, Immediate(kSmiTagMask));
1383 __ j(zero, true_label);
1384
1385 // Test for double values. Zero is false.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001386 Label call_stub;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001387 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 factory()->heap_number_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001389 __ j(not_equal, &call_stub, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001390 __ fldz();
1391 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1392 __ FCmp();
1393 __ j(zero, false_label);
1394 __ jmp(true_label);
1395
1396 // The conversion stub doesn't cause garbage collections so it's
1397 // safe to not record a safepoint after the call.
1398 __ bind(&call_stub);
1399 ToBooleanStub stub;
1400 __ pushad();
1401 __ push(reg);
1402 __ CallStub(&stub);
1403 __ test(eax, Operand(eax));
1404 __ popad();
1405 EmitBranch(true_block, false_block, not_zero);
1406 }
1407 }
1408}
1409
1410
1411void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
1412 block = chunk_->LookupDestination(block);
1413 int next_block = GetNextEmittedBlock(current_block_);
1414 if (block != next_block) {
1415 // Perform stack overflow check if this goto needs it before jumping.
1416 if (deferred_stack_check != NULL) {
1417 ExternalReference stack_limit =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 __ cmp(esp, Operand::StaticVariable(stack_limit));
1420 __ j(above_equal, chunk_->GetAssemblyLabel(block));
1421 __ jmp(deferred_stack_check->entry());
1422 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1423 } else {
1424 __ jmp(chunk_->GetAssemblyLabel(block));
1425 }
1426 }
1427}
1428
1429
1430void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001431 PushSafepointRegistersScope scope(this);
1432 CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001433}
1434
1435void LCodeGen::DoGoto(LGoto* instr) {
1436 class DeferredStackCheck: public LDeferredCode {
1437 public:
1438 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1439 : LDeferredCode(codegen), instr_(instr) { }
1440 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1441 private:
1442 LGoto* instr_;
1443 };
1444
1445 DeferredStackCheck* deferred = NULL;
1446 if (instr->include_stack_check()) {
1447 deferred = new DeferredStackCheck(this, instr);
1448 }
1449 EmitGoto(instr->block_id(), deferred);
1450}
1451
1452
1453Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1454 Condition cond = no_condition;
1455 switch (op) {
1456 case Token::EQ:
1457 case Token::EQ_STRICT:
1458 cond = equal;
1459 break;
1460 case Token::LT:
1461 cond = is_unsigned ? below : less;
1462 break;
1463 case Token::GT:
1464 cond = is_unsigned ? above : greater;
1465 break;
1466 case Token::LTE:
1467 cond = is_unsigned ? below_equal : less_equal;
1468 break;
1469 case Token::GTE:
1470 cond = is_unsigned ? above_equal : greater_equal;
1471 break;
1472 case Token::IN:
1473 case Token::INSTANCEOF:
1474 default:
1475 UNREACHABLE();
1476 }
1477 return cond;
1478}
1479
1480
1481void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
1482 if (right->IsConstantOperand()) {
1483 __ cmp(ToOperand(left), ToImmediate(right));
1484 } else {
1485 __ cmp(ToRegister(left), ToOperand(right));
1486 }
1487}
1488
1489
1490void LCodeGen::DoCmpID(LCmpID* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001491 LOperand* left = instr->InputAt(0);
1492 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001493 LOperand* result = instr->result();
1494
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001495 Label unordered;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001496 if (instr->is_double()) {
1497 // Don't base result on EFLAGS when a NaN is involved. Instead
1498 // jump to the unordered case, which produces a false value.
1499 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001500 __ j(parity_even, &unordered, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001501 } else {
1502 EmitCmpI(left, right);
1503 }
1504
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001505 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506 Condition cc = TokenToCondition(instr->op(), instr->is_double());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001507 __ mov(ToRegister(result), factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001508 __ j(cc, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001509
1510 __ bind(&unordered);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001511 __ mov(ToRegister(result), factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001512 __ bind(&done);
1513}
1514
1515
1516void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001517 LOperand* left = instr->InputAt(0);
1518 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001519 int false_block = chunk_->LookupDestination(instr->false_block_id());
1520 int true_block = chunk_->LookupDestination(instr->true_block_id());
1521
1522 if (instr->is_double()) {
1523 // Don't base result on EFLAGS when a NaN is involved. Instead
1524 // jump to the false block.
1525 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1526 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1527 } else {
1528 EmitCmpI(left, right);
1529 }
1530
1531 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1532 EmitBranch(true_block, false_block, cc);
1533}
1534
1535
1536void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001537 Register left = ToRegister(instr->InputAt(0));
1538 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001539 Register result = ToRegister(instr->result());
1540
1541 __ cmp(left, Operand(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 __ mov(result, factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001543 Label done;
1544 __ j(equal, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001546 __ bind(&done);
1547}
1548
1549
1550void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001551 Register left = ToRegister(instr->InputAt(0));
1552 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001553 int false_block = chunk_->LookupDestination(instr->false_block_id());
1554 int true_block = chunk_->LookupDestination(instr->true_block_id());
1555
1556 __ cmp(left, Operand(right));
1557 EmitBranch(true_block, false_block, equal);
1558}
1559
1560
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001561void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) {
1562 Register left = ToRegister(instr->InputAt(0));
1563 Register right = ToRegister(instr->InputAt(1));
1564 Register result = ToRegister(instr->result());
1565
1566 Label done;
1567 __ cmp(left, Operand(right));
1568 __ mov(result, factory()->false_value());
1569 __ j(not_equal, &done, Label::kNear);
1570 __ mov(result, factory()->true_value());
1571 __ bind(&done);
1572}
1573
1574
1575void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
1576 Register left = ToRegister(instr->InputAt(0));
1577 Register right = ToRegister(instr->InputAt(1));
1578 int false_block = chunk_->LookupDestination(instr->false_block_id());
1579 int true_block = chunk_->LookupDestination(instr->true_block_id());
1580
1581 __ cmp(left, Operand(right));
1582 EmitBranch(true_block, false_block, equal);
1583}
1584
1585
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586void LCodeGen::DoIsNull(LIsNull* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001587 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001588 Register result = ToRegister(instr->result());
1589
1590 // TODO(fsc): If the expression is known to be a smi, then it's
1591 // definitely not null. Materialize false.
1592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001594 if (instr->is_strict()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001595 __ mov(result, factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001596 Label done;
1597 __ j(equal, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599 __ bind(&done);
1600 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001601 Label true_value, false_value, done;
1602 __ j(equal, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001603 __ cmp(reg, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001604 __ j(equal, &true_value, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001605 __ test(reg, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001606 __ j(zero, &false_value, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001607 // Check for undetectable objects by looking in the bit field in
1608 // the map. The object has already been smi checked.
1609 Register scratch = result;
1610 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1611 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1612 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001613 __ j(not_zero, &true_value, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001614 __ bind(&false_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 __ mov(result, factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001616 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001618 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001619 __ bind(&done);
1620 }
1621}
1622
1623
1624void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001625 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001626
1627 // TODO(fsc): If the expression is known to be a smi, then it's
1628 // definitely not null. Jump to the false block.
1629
1630 int true_block = chunk_->LookupDestination(instr->true_block_id());
1631 int false_block = chunk_->LookupDestination(instr->false_block_id());
1632
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001633 __ cmp(reg, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001634 if (instr->is_strict()) {
1635 EmitBranch(true_block, false_block, equal);
1636 } else {
1637 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1638 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1639 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 __ cmp(reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641 __ j(equal, true_label);
1642 __ test(reg, Immediate(kSmiTagMask));
1643 __ j(zero, false_label);
1644 // Check for undetectable objects by looking in the bit field in
1645 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001646 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001647 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1648 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1649 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1650 EmitBranch(true_block, false_block, not_zero);
1651 }
1652}
1653
1654
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001655Condition LCodeGen::EmitIsObject(Register input,
1656 Register temp1,
1657 Register temp2,
1658 Label* is_not_object,
1659 Label* is_object) {
1660 ASSERT(!input.is(temp1));
1661 ASSERT(!input.is(temp2));
1662 ASSERT(!temp1.is(temp2));
1663
1664 __ test(input, Immediate(kSmiTagMask));
1665 __ j(equal, is_not_object);
1666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001668 __ j(equal, is_object);
1669
1670 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1671 // Undetectable objects behave like undefined.
1672 __ movzx_b(temp2, FieldOperand(temp1, Map::kBitFieldOffset));
1673 __ test(temp2, Immediate(1 << Map::kIsUndetectable));
1674 __ j(not_zero, is_not_object);
1675
1676 __ movzx_b(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001677 __ cmp(temp2, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001678 __ j(below, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001679 __ cmp(temp2, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001680 return below_equal;
1681}
1682
1683
1684void LCodeGen::DoIsObject(LIsObject* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001685 Register reg = ToRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001687 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001688 Label is_false, is_true, done;
1689
1690 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1691 __ j(true_cond, &is_true);
1692
1693 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001694 __ mov(result, factory()->false_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001695 __ jmp(&done);
1696
1697 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 __ mov(result, factory()->true_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001699
1700 __ bind(&done);
1701}
1702
1703
1704void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001705 Register reg = ToRegister(instr->InputAt(0));
1706 Register temp = ToRegister(instr->TempAt(0));
1707 Register temp2 = ToRegister(instr->TempAt(1));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001708
1709 int true_block = chunk_->LookupDestination(instr->true_block_id());
1710 int false_block = chunk_->LookupDestination(instr->false_block_id());
1711 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1712 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1713
1714 Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label);
1715
1716 EmitBranch(true_block, false_block, true_cond);
1717}
1718
1719
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001720void LCodeGen::DoIsSmi(LIsSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001721 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001722 Register result = ToRegister(instr->result());
1723
1724 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1725 __ test(input, Immediate(kSmiTagMask));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 __ mov(result, factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001727 Label done;
1728 __ j(zero, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001730 __ bind(&done);
1731}
1732
1733
1734void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001735 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001736
1737 int true_block = chunk_->LookupDestination(instr->true_block_id());
1738 int false_block = chunk_->LookupDestination(instr->false_block_id());
1739
1740 __ test(input, Immediate(kSmiTagMask));
1741 EmitBranch(true_block, false_block, zero);
1742}
1743
1744
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001745void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
1746 Register input = ToRegister(instr->InputAt(0));
1747 Register result = ToRegister(instr->result());
1748
1749 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1750 Label false_label, done;
1751 STATIC_ASSERT(kSmiTag == 0);
1752 __ test(input, Immediate(kSmiTagMask));
1753 __ j(zero, &false_label, Label::kNear);
1754 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1755 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
1756 1 << Map::kIsUndetectable);
1757 __ j(zero, &false_label, Label::kNear);
1758 __ mov(result, factory()->true_value());
1759 __ jmp(&done);
1760 __ bind(&false_label);
1761 __ mov(result, factory()->false_value());
1762 __ bind(&done);
1763}
1764
1765
1766void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1767 Register input = ToRegister(instr->InputAt(0));
1768 Register temp = ToRegister(instr->TempAt(0));
1769
1770 int true_block = chunk_->LookupDestination(instr->true_block_id());
1771 int false_block = chunk_->LookupDestination(instr->false_block_id());
1772
1773 STATIC_ASSERT(kSmiTag == 0);
1774 __ test(input, Immediate(kSmiTagMask));
1775 __ j(zero, chunk_->GetAssemblyLabel(false_block));
1776 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1777 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1778 1 << Map::kIsUndetectable);
1779 EmitBranch(true_block, false_block, not_zero);
1780}
1781
1782
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001783static InstanceType TestType(HHasInstanceType* instr) {
1784 InstanceType from = instr->from();
1785 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 if (from == FIRST_TYPE) return to;
1787 ASSERT(from == to || to == LAST_TYPE);
1788 return from;
1789}
1790
1791
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001792static Condition BranchCondition(HHasInstanceType* instr) {
1793 InstanceType from = instr->from();
1794 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001795 if (from == to) return equal;
1796 if (to == LAST_TYPE) return above_equal;
1797 if (from == FIRST_TYPE) return below_equal;
1798 UNREACHABLE();
1799 return equal;
1800}
1801
1802
1803void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001804 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001805 Register result = ToRegister(instr->result());
1806
1807 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1808 __ test(input, Immediate(kSmiTagMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001809 Label done, is_false;
1810 __ j(zero, &is_false, Label::kNear);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001811 __ CmpObjectType(input, TestType(instr->hydrogen()), result);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001812 __ j(NegateCondition(BranchCondition(instr->hydrogen())),
1813 &is_false, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 __ mov(result, factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001815 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001816 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001818 __ bind(&done);
1819}
1820
1821
1822void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001823 Register input = ToRegister(instr->InputAt(0));
1824 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001825
1826 int true_block = chunk_->LookupDestination(instr->true_block_id());
1827 int false_block = chunk_->LookupDestination(instr->false_block_id());
1828
1829 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1830
1831 __ test(input, Immediate(kSmiTagMask));
1832 __ j(zero, false_label);
1833
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001834 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1835 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001836}
1837
1838
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001839void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1840 Register input = ToRegister(instr->InputAt(0));
1841 Register result = ToRegister(instr->result());
1842
1843 if (FLAG_debug_code) {
1844 __ AbortIfNotString(input);
1845 }
1846
1847 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
1848 __ IndexFromHash(result, result);
1849}
1850
1851
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001852void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001853 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001854 Register result = ToRegister(instr->result());
1855
1856 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001858 __ test(FieldOperand(input, String::kHashFieldOffset),
1859 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001860 Label done;
1861 __ j(zero, &done, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863 __ bind(&done);
1864}
1865
1866
1867void LCodeGen::DoHasCachedArrayIndexAndBranch(
1868 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001869 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001870
1871 int true_block = chunk_->LookupDestination(instr->true_block_id());
1872 int false_block = chunk_->LookupDestination(instr->false_block_id());
1873
1874 __ test(FieldOperand(input, String::kHashFieldOffset),
1875 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001876 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001877}
1878
1879
1880// Branches to a label or falls through with the answer in the z flag. Trashes
1881// the temp registers, but not the input. Only input and temp2 may alias.
1882void LCodeGen::EmitClassOfTest(Label* is_true,
1883 Label* is_false,
1884 Handle<String>class_name,
1885 Register input,
1886 Register temp,
1887 Register temp2) {
1888 ASSERT(!input.is(temp));
1889 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
1890 __ test(input, Immediate(kSmiTagMask));
1891 __ j(zero, is_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001892 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001893 __ j(below, is_false);
1894
1895 // Map is now in temp.
1896 // Functions have class 'Function'.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001897 __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001898 if (class_name->IsEqualTo(CStrVector("Function"))) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001899 __ j(above_equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001900 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001901 __ j(above_equal, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001902 }
1903
1904 // Check if the constructor in the map is a function.
1905 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
1906
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001907 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
1908 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
1909 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
1910 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
1911 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
1912 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001913
1914 // Objects with a non-function constructor have class 'Object'.
1915 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1916 if (class_name->IsEqualTo(CStrVector("Object"))) {
1917 __ j(not_equal, is_true);
1918 } else {
1919 __ j(not_equal, is_false);
1920 }
1921
1922 // temp now contains the constructor function. Grab the
1923 // instance class name from there.
1924 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1925 __ mov(temp, FieldOperand(temp,
1926 SharedFunctionInfo::kInstanceClassNameOffset));
1927 // The class name we are testing against is a symbol because it's a literal.
1928 // The name in the constructor is a symbol because of the way the context is
1929 // booted. This routine isn't expected to work for random API-created
1930 // classes and it doesn't have to because you can't access it with natives
1931 // syntax. Since both sides are symbols it is sufficient to use an identity
1932 // comparison.
1933 __ cmp(temp, class_name);
1934 // End with the answer in the z flag.
1935}
1936
1937
1938void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001939 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001940 Register result = ToRegister(instr->result());
1941 ASSERT(input.is(result));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001942 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001943 Handle<String> class_name = instr->hydrogen()->class_name();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001944 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001945 Label is_true, is_false;
1946
1947 EmitClassOfTest(&is_true, &is_false, class_name, input, temp, input);
1948
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001949 __ j(not_equal, &is_false, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001950
1951 __ bind(&is_true);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 __ mov(result, factory()->true_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001953 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001954
1955 __ bind(&is_false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 __ mov(result, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001957 __ bind(&done);
1958}
1959
1960
1961void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001962 Register input = ToRegister(instr->InputAt(0));
1963 Register temp = ToRegister(instr->TempAt(0));
1964 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001965 if (input.is(temp)) {
1966 // Swap.
1967 Register swapper = temp;
1968 temp = temp2;
1969 temp2 = swapper;
1970 }
1971 Handle<String> class_name = instr->hydrogen()->class_name();
1972
1973 int true_block = chunk_->LookupDestination(instr->true_block_id());
1974 int false_block = chunk_->LookupDestination(instr->false_block_id());
1975
1976 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1977 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1978
1979 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1980
1981 EmitBranch(true_block, false_block, equal);
1982}
1983
1984
1985void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001986 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001987 int true_block = instr->true_block_id();
1988 int false_block = instr->false_block_id();
1989
1990 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1991 EmitBranch(true_block, false_block, equal);
1992}
1993
1994
1995void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001996 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001997 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001998 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001999 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002000
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002001 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002002 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002003 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002005 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002006 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 __ bind(&done);
2009}
2010
2011
2012void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002013 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002014 int true_block = chunk_->LookupDestination(instr->true_block_id());
2015 int false_block = chunk_->LookupDestination(instr->false_block_id());
2016
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002017 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002018 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002019 __ test(eax, Operand(eax));
2020 EmitBranch(true_block, false_block, zero);
2021}
2022
2023
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002024void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2025 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2026 public:
2027 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2028 LInstanceOfKnownGlobal* instr)
2029 : LDeferredCode(codegen), instr_(instr) { }
2030 virtual void Generate() {
2031 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
2032 }
2033
2034 Label* map_check() { return &map_check_; }
2035
2036 private:
2037 LInstanceOfKnownGlobal* instr_;
2038 Label map_check_;
2039 };
2040
2041 DeferredInstanceOfKnownGlobal* deferred;
2042 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
2043
2044 Label done, false_result;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002045 Register object = ToRegister(instr->InputAt(0));
2046 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002047
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002048 // A Smi is not an instance of anything.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002049 __ test(object, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002050 __ j(zero, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002051
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002052 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002053 // hole value will be patched to the last map/result pair generated by the
2054 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002055 Label cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002056 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002057 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2058 __ bind(deferred->map_check()); // Label for calculating code patching.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002060 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002062 __ jmp(&done);
2063
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002064 // The inlined call site cache did not match. Check for null and string
2065 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002066 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002067 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002069 __ j(equal, &false_result);
2070
2071 // String values are not instances of anything.
2072 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2073 __ j(is_string, &false_result);
2074
2075 // Go to the deferred code.
2076 __ jmp(deferred->entry());
2077
2078 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002079 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002080
2081 // Here result has either true or false. Deferred code also produces true or
2082 // false object.
2083 __ bind(deferred->exit());
2084 __ bind(&done);
2085}
2086
2087
2088void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2089 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002090 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002091
2092 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2093 flags = static_cast<InstanceofStub::Flags>(
2094 flags | InstanceofStub::kArgsInRegisters);
2095 flags = static_cast<InstanceofStub::Flags>(
2096 flags | InstanceofStub::kCallSiteInlineCheck);
2097 flags = static_cast<InstanceofStub::Flags>(
2098 flags | InstanceofStub::kReturnTrueFalseObject);
2099 InstanceofStub stub(flags);
2100
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002101 // Get the temp register reserved by the instruction. This needs to be a
2102 // register which is pushed last by PushSafepointRegisters as top of the
2103 // stack is used to pass the offset to the location of the map check to
2104 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002105 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002106 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002107 __ mov(InstanceofStub::right(), Immediate(instr->function()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002108 static const int kAdditionalDelta = 16;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002109 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002110 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002111 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002112 CallCodeGeneric(stub.GetCode(),
2113 RelocInfo::CODE_TARGET,
2114 instr,
2115 RESTORE_CONTEXT,
2116 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002117 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002118 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002119}
2120
2121
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122static Condition ComputeCompareCondition(Token::Value op) {
2123 switch (op) {
2124 case Token::EQ_STRICT:
2125 case Token::EQ:
2126 return equal;
2127 case Token::LT:
2128 return less;
2129 case Token::GT:
2130 return greater;
2131 case Token::LTE:
2132 return less_equal;
2133 case Token::GTE:
2134 return greater_equal;
2135 default:
2136 UNREACHABLE();
2137 return no_condition;
2138 }
2139}
2140
2141
2142void LCodeGen::DoCmpT(LCmpT* instr) {
2143 Token::Value op = instr->op();
2144
2145 Handle<Code> ic = CompareIC::GetUninitialized(op);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002146 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002147
2148 Condition condition = ComputeCompareCondition(op);
2149 if (op == Token::GT || op == Token::LTE) {
2150 condition = ReverseCondition(condition);
2151 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002152 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002153 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002154 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002155 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002156 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002157 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002158 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002159 __ bind(&done);
2160}
2161
2162
2163void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
2164 Token::Value op = instr->op();
2165 int true_block = chunk_->LookupDestination(instr->true_block_id());
2166 int false_block = chunk_->LookupDestination(instr->false_block_id());
2167
2168 Handle<Code> ic = CompareIC::GetUninitialized(op);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002169 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170
2171 // The compare stub expects compare condition and the input operands
2172 // reversed for GT and LTE.
2173 Condition condition = ComputeCompareCondition(op);
2174 if (op == Token::GT || op == Token::LTE) {
2175 condition = ReverseCondition(condition);
2176 }
2177 __ test(eax, Operand(eax));
2178 EmitBranch(true_block, false_block, condition);
2179}
2180
2181
2182void LCodeGen::DoReturn(LReturn* instr) {
2183 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002184 // Preserve the return value on the stack and rely on the runtime call
2185 // to return the value in the same register. We're leaving the code
2186 // managed by the register allocator and tearing down the frame, it's
2187 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002188 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002189 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002190 __ CallRuntime(Runtime::kTraceExit, 1);
2191 }
2192 __ mov(esp, ebp);
2193 __ pop(ebp);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002194 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002195}
2196
2197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002198void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 Register result = ToRegister(instr->result());
2200 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
2201 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002202 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002203 DeoptimizeIf(equal, instr->environment());
2204 }
2205}
2206
2207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002208void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2209 ASSERT(ToRegister(instr->context()).is(esi));
2210 ASSERT(ToRegister(instr->global_object()).is(eax));
2211 ASSERT(ToRegister(instr->result()).is(eax));
2212
2213 __ mov(ecx, instr->name());
2214 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2215 RelocInfo::CODE_TARGET_CONTEXT;
2216 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002217 CallCode(ic, mode, instr, CONTEXT_ADJUSTED);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002218}
2219
2220
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002221void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002222 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002223 Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
2224
2225 // If the cell we are storing to contains the hole it could have
2226 // been deleted from the property dictionary. In that case, we need
2227 // to update the property details in the property dictionary to mark
2228 // it as no longer deleted. We deoptimize in that case.
2229 if (instr->hydrogen()->check_hole_value()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230 __ cmp(cell_operand, factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002231 DeoptimizeIf(equal, instr->environment());
2232 }
2233
2234 // Store the value.
2235 __ mov(cell_operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002236}
2237
2238
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002239void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2240 ASSERT(ToRegister(instr->context()).is(esi));
2241 ASSERT(ToRegister(instr->global_object()).is(edx));
2242 ASSERT(ToRegister(instr->value()).is(eax));
2243
2244 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002245 Handle<Code> ic = instr->strict_mode()
2246 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2247 : isolate()->builtins()->StoreIC_Initialize();
2248 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr, CONTEXT_ADJUSTED);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002249}
2250
2251
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002252void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002253 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002254 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002255 __ mov(result, ContextOperand(context, instr->slot_index()));
2256}
2257
2258
2259void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2260 Register context = ToRegister(instr->context());
2261 Register value = ToRegister(instr->value());
2262 __ mov(ContextOperand(context, instr->slot_index()), value);
2263 if (instr->needs_write_barrier()) {
2264 Register temp = ToRegister(instr->TempAt(0));
2265 int offset = Context::SlotOffset(instr->slot_index());
2266 __ RecordWrite(context, offset, value, temp);
2267 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002268}
2269
2270
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002271void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002272 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002273 Register result = ToRegister(instr->result());
2274 if (instr->hydrogen()->is_in_object()) {
2275 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2276 } else {
2277 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2278 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2279 }
2280}
2281
2282
lrn@chromium.org1c092762011-05-09 09:42:16 +00002283void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2284 Register object,
2285 Handle<Map> type,
2286 Handle<String> name) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002287 LookupResult lookup;
2288 type->LookupInDescriptors(NULL, *name, &lookup);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002289 ASSERT(lookup.IsProperty() &&
2290 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2291 if (lookup.type() == FIELD) {
2292 int index = lookup.GetLocalFieldIndexFromMap(*type);
2293 int offset = index * kPointerSize;
2294 if (index < 0) {
2295 // Negative property indices are in-object properties, indexed
2296 // from the end of the fixed part of the object.
2297 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2298 } else {
2299 // Non-negative property indices are in the properties array.
2300 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2301 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2302 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002303 } else {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002304 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
2305 LoadHeapObject(result, Handle<HeapObject>::cast(function));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002306 }
2307}
2308
2309
2310void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2311 Register object = ToRegister(instr->object());
2312 Register result = ToRegister(instr->result());
2313
2314 int map_count = instr->hydrogen()->types()->length();
2315 Handle<String> name = instr->hydrogen()->name();
2316 if (map_count == 0) {
2317 ASSERT(instr->hydrogen()->need_generic());
2318 __ mov(ecx, name);
2319 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002320 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002321 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002322 Label done;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002323 for (int i = 0; i < map_count - 1; ++i) {
2324 Handle<Map> map = instr->hydrogen()->types()->at(i);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002325 Label next;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002326 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002327 __ j(not_equal, &next, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002328 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002329 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002330 __ bind(&next);
2331 }
2332 Handle<Map> map = instr->hydrogen()->types()->last();
2333 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2334 if (instr->hydrogen()->need_generic()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002335 Label generic;
2336 __ j(not_equal, &generic, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002337 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002338 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002339 __ bind(&generic);
2340 __ mov(ecx, name);
2341 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002342 CallCode(ic, RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002343 } else {
2344 DeoptimizeIf(not_equal, instr->environment());
lrn@chromium.org1c092762011-05-09 09:42:16 +00002345 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002346 }
2347 __ bind(&done);
2348 }
2349}
2350
2351
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002352void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002353 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002354 ASSERT(ToRegister(instr->object()).is(eax));
2355 ASSERT(ToRegister(instr->result()).is(eax));
2356
2357 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002358 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002359 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002360}
2361
2362
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002363void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2364 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002365 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002366 Register result = ToRegister(instr->result());
2367
2368 // Check that the function really is a function.
2369 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2370 DeoptimizeIf(not_equal, instr->environment());
2371
2372 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002373 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002374 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2375 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002376 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002377
2378 // Get the prototype or initial map from the function.
2379 __ mov(result,
2380 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2381
2382 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002383 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002384 DeoptimizeIf(equal, instr->environment());
2385
2386 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002387 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002388 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002389 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002390
2391 // Get the prototype from the initial map.
2392 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002393 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002394
2395 // Non-instance prototype: Fetch prototype from constructor field
2396 // in the function's map.
2397 __ bind(&non_instance);
2398 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2399
2400 // All done.
2401 __ bind(&done);
2402}
2403
2404
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002405void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002406 Register result = ToRegister(instr->result());
2407 Register input = ToRegister(instr->InputAt(0));
2408 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002409 if (FLAG_debug_code) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002410 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002411 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002412 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002413 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002414 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002415 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002416 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002417 Register temp((result.is(eax)) ? ebx : eax);
2418 __ push(temp);
2419 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
2420 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
2421 __ sub(Operand(temp), Immediate(FIRST_EXTERNAL_ARRAY_TYPE));
2422 __ cmp(Operand(temp), Immediate(kExternalArrayTypeCount));
2423 __ pop(temp);
2424 __ Check(below, "Check for fast elements or pixel array failed.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002425 __ bind(&done);
2426 }
2427}
2428
2429
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002430void LCodeGen::DoLoadExternalArrayPointer(
2431 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002432 Register result = ToRegister(instr->result());
2433 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002434 __ mov(result, FieldOperand(input,
2435 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002436}
2437
2438
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002439void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2440 Register arguments = ToRegister(instr->arguments());
2441 Register length = ToRegister(instr->length());
2442 Operand index = ToOperand(instr->index());
2443 Register result = ToRegister(instr->result());
2444
2445 __ sub(length, index);
2446 DeoptimizeIf(below_equal, instr->environment());
2447
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002448 // There are two words between the frame pointer and the last argument.
2449 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002450 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2451}
2452
2453
2454void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
2455 Register elements = ToRegister(instr->elements());
2456 Register key = ToRegister(instr->key());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002457 Register result = ToRegister(instr->result());
2458 ASSERT(result.is(elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002459
2460 // Load the result.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002461 __ mov(result, FieldOperand(elements,
2462 key,
2463 times_pointer_size,
2464 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002465
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002466 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002467 if (instr->hydrogen()->RequiresHoleCheck()) {
2468 __ cmp(result, factory()->the_hole_value());
2469 DeoptimizeIf(equal, instr->environment());
2470 }
2471}
2472
2473
2474Operand LCodeGen::BuildExternalArrayOperand(LOperand* external_pointer,
2475 LOperand* key,
2476 ExternalArrayType array_type) {
2477 Register external_pointer_reg = ToRegister(external_pointer);
2478 int shift_size = ExternalArrayTypeToShiftSize(array_type);
2479 if (key->IsConstantOperand()) {
2480 int constant_value = ToInteger32(LConstantOperand::cast(key));
2481 if (constant_value & 0xF0000000) {
2482 Abort("array index constant value too big");
2483 }
2484 return Operand(external_pointer_reg, constant_value * (1 << shift_size));
2485 } else {
2486 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
2487 return Operand(external_pointer_reg, ToRegister(key), scale_factor, 0);
2488 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002489}
2490
2491
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002492void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2493 LLoadKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002494 ExternalArrayType array_type = instr->array_type();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002495 Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
2496 instr->key(), array_type));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002497 if (array_type == kExternalFloatArray) {
2498 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002499 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002500 __ cvtss2sd(result, result);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002501 } else if (array_type == kExternalDoubleArray) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002502 __ movdbl(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002503 } else {
2504 Register result(ToRegister(instr->result()));
2505 switch (array_type) {
2506 case kExternalByteArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002507 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002508 break;
2509 case kExternalUnsignedByteArray:
2510 case kExternalPixelArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002511 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002512 break;
2513 case kExternalShortArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002514 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002515 break;
2516 case kExternalUnsignedShortArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002517 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002518 break;
2519 case kExternalIntArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002520 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002521 break;
2522 case kExternalUnsignedIntArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002523 __ mov(result, operand);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002524 __ test(result, Operand(result));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002525 // TODO(danno): we could be more clever here, perhaps having a special
2526 // version of the stub that detects if the overflow case actually
2527 // happens, and generate code that returns a double rather than int.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002528 DeoptimizeIf(negative, instr->environment());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002529 break;
2530 case kExternalFloatArray:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002531 case kExternalDoubleArray:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002532 UNREACHABLE();
2533 break;
2534 }
2535 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002536}
2537
2538
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002539void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002540 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002541 ASSERT(ToRegister(instr->object()).is(edx));
2542 ASSERT(ToRegister(instr->key()).is(eax));
2543
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002544 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002545 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002546}
2547
2548
2549void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2550 Register result = ToRegister(instr->result());
2551
2552 // Check for arguments adapter frame.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002553 Label done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002554 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2555 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2556 __ cmp(Operand(result),
2557 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002558 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002559
2560 // No arguments adaptor frame.
2561 __ mov(result, Operand(ebp));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002562 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002563
2564 // Arguments adaptor frame present.
2565 __ bind(&adapted);
2566 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2567
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002568 // Result is the frame pointer for the frame if not adapted and for the real
2569 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002570 __ bind(&done);
2571}
2572
2573
2574void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002575 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002576 Register result = ToRegister(instr->result());
2577
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002578 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002579
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002580 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002581 __ cmp(ebp, elem);
2582 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002583 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002584
2585 // Arguments adaptor frame present. Get argument length from there.
2586 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2587 __ mov(result, Operand(result,
2588 ArgumentsAdaptorFrameConstants::kLengthOffset));
2589 __ SmiUntag(result);
2590
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002591 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002592 __ bind(&done);
2593}
2594
2595
2596void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2597 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002598 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002599 Register length = ToRegister(instr->length());
2600 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002601 Register scratch = ToRegister(instr->TempAt(0));
2602 ASSERT(receiver.is(eax)); // Used for parameter count.
2603 ASSERT(function.is(edi)); // Required by InvokeFunction.
2604 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002605
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002606 // If the receiver is null or undefined, we have to pass the global
2607 // object as a receiver to normal functions. Values have to be
2608 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002609 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002610
2611 // Do not transform the receiver to object for strict mode
2612 // functions.
2613 __ mov(scratch,
2614 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2615 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
2616 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
2617 __ j(not_equal, &receiver_ok, Label::kNear);
2618
2619 // Do not transform the receiver to object for builtins.
2620 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
2621 1 << SharedFunctionInfo::kNativeBitWithinByte);
2622 __ j(not_equal, &receiver_ok, Label::kNear);
2623
2624 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002625 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002626 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002627 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002628 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002629
2630 // The receiver should be a JS object.
2631 __ test(receiver, Immediate(kSmiTagMask));
2632 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002633 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002634 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002635 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002636
2637 __ bind(&global_object);
2638 // TODO(kmillikin): We have a hydrogen value for the global object. See
2639 // if it's better to use it than to explicitly fetch it from the context
2640 // here.
2641 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2642 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002643 __ mov(receiver,
2644 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002645 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002646
2647 // Copy the arguments to this function possibly from the
2648 // adaptor frame below it.
2649 const uint32_t kArgumentsLimit = 1 * KB;
2650 __ cmp(length, kArgumentsLimit);
2651 DeoptimizeIf(above, instr->environment());
2652
2653 __ push(receiver);
2654 __ mov(receiver, length);
2655
2656 // Loop through the arguments pushing them onto the execution
2657 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002658 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002659 // length is a small non-negative integer, due to the test above.
2660 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002661 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002662 __ bind(&loop);
2663 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2664 __ dec(length);
2665 __ j(not_zero, &loop);
2666
2667 // Invoke the function.
2668 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002669 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2670 LPointerMap* pointers = instr->pointer_map();
2671 LEnvironment* env = instr->deoptimization_environment();
2672 RecordPosition(pointers->position());
2673 RegisterEnvironmentForDeoptimization(env);
2674 SafepointGenerator safepoint_generator(this,
2675 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002676 env->deoptimization_index());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002677 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002678 __ InvokeFunction(function, actual, CALL_FUNCTION,
2679 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002680}
2681
2682
2683void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002684 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002685 if (argument->IsConstantOperand()) {
2686 __ push(ToImmediate(argument));
2687 } else {
2688 __ push(ToOperand(argument));
2689 }
2690}
2691
2692
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002693void LCodeGen::DoThisFunction(LThisFunction* instr) {
2694 Register result = ToRegister(instr->result());
2695 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
2696}
2697
2698
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002699void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002700 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002701 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002702}
2703
2704
2705void LCodeGen::DoOuterContext(LOuterContext* instr) {
2706 Register context = ToRegister(instr->context());
2707 Register result = ToRegister(instr->result());
2708 __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2709 __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
2710}
2711
2712
2713void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2714 Register context = ToRegister(instr->context());
2715 Register result = ToRegister(instr->result());
2716 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002717}
2718
2719
2720void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002721 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002722 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002723 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002724}
2725
2726
2727void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2728 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002729 LInstruction* instr,
2730 CallKind call_kind) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002731 // Change context if needed.
2732 bool change_context =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002733 (info()->closure()->context() != function->context()) ||
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002734 scope()->contains_with() ||
2735 (scope()->num_heap_slots() > 0);
2736 if (change_context) {
2737 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002738 } else {
2739 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002740 }
2741
2742 // Set eax to arguments count if adaption is not needed. Assumes that eax
2743 // is available to write to at this point.
2744 if (!function->NeedsArgumentsAdaption()) {
2745 __ mov(eax, arity);
2746 }
2747
2748 LPointerMap* pointers = instr->pointer_map();
2749 RecordPosition(pointers->position());
2750
2751 // Invoke function.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002752 __ SetCallKind(ecx, call_kind);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002753 if (*function == *info()->closure()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002754 __ CallSelf();
2755 } else {
2756 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2757 }
2758
2759 // Setup deoptimization.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002760 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002761}
2762
2763
2764void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2765 ASSERT(ToRegister(instr->result()).is(eax));
2766 __ mov(edi, instr->function());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002767 CallKnownFunction(instr->function(),
2768 instr->arity(),
2769 instr,
2770 CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002771}
2772
2773
2774void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002775 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002776 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002777 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002778 DeoptimizeIf(not_equal, instr->environment());
2779
2780 Label done;
2781 Register tmp = input_reg.is(eax) ? ecx : eax;
2782 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2783
2784 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002785 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002786
2787 Label negative;
2788 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002789 // Check the sign of the argument. If the argument is positive, just
2790 // return it. We do not need to patch the stack since |input| and
2791 // |result| are the same register and |input| will be restored
2792 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002793 __ test(tmp, Immediate(HeapNumber::kSignMask));
2794 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002795 __ jmp(&done);
2796
2797 __ bind(&negative);
2798
2799 Label allocated, slow;
2800 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2801 __ jmp(&allocated);
2802
2803 // Slow case: Call the runtime system to do the number allocation.
2804 __ bind(&slow);
2805
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002806 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
2807
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002808 // Set the pointer to the new heap number in tmp.
2809 if (!tmp.is(eax)) __ mov(tmp, eax);
2810
2811 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002812 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002813
2814 __ bind(&allocated);
2815 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2816 __ and_(tmp2, ~HeapNumber::kSignMask);
2817 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2818 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2819 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002820 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002821
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002822 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002823}
2824
2825
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002826void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2827 Register input_reg = ToRegister(instr->InputAt(0));
2828 __ test(input_reg, Operand(input_reg));
2829 Label is_positive;
2830 __ j(not_sign, &is_positive);
2831 __ neg(input_reg);
2832 __ test(input_reg, Operand(input_reg));
2833 DeoptimizeIf(negative, instr->environment());
2834 __ bind(&is_positive);
2835}
2836
2837
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002838void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2839 // Class for deferred case.
2840 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2841 public:
2842 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2843 LUnaryMathOperation* instr)
2844 : LDeferredCode(codegen), instr_(instr) { }
2845 virtual void Generate() {
2846 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2847 }
2848 private:
2849 LUnaryMathOperation* instr_;
2850 };
2851
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002852 ASSERT(instr->InputAt(0)->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002853 Representation r = instr->hydrogen()->value()->representation();
2854
2855 if (r.IsDouble()) {
2856 XMMRegister scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002857 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002858 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002859 __ subsd(scratch, input_reg);
2860 __ pand(input_reg, scratch);
2861 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002862 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863 } else { // Tagged case.
2864 DeferredMathAbsTaggedHeapNumber* deferred =
2865 new DeferredMathAbsTaggedHeapNumber(this, instr);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002866 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002867 // Smi check.
2868 __ test(input_reg, Immediate(kSmiTagMask));
2869 __ j(not_zero, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002870 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002871 __ bind(deferred->exit());
2872 }
2873}
2874
2875
2876void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2877 XMMRegister xmm_scratch = xmm0;
2878 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002879 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002880 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002881 __ ucomisd(input_reg, xmm_scratch);
2882
2883 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2884 DeoptimizeIf(below_equal, instr->environment());
2885 } else {
2886 DeoptimizeIf(below, instr->environment());
2887 }
2888
2889 // Use truncating instruction (OK because input is positive).
2890 __ cvttsd2si(output_reg, Operand(input_reg));
2891
2892 // Overflow is signalled with minint.
2893 __ cmp(output_reg, 0x80000000u);
2894 DeoptimizeIf(equal, instr->environment());
2895}
2896
2897
2898void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2899 XMMRegister xmm_scratch = xmm0;
2900 Register output_reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002901 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002902
danno@chromium.org160a7b02011-04-18 15:51:38 +00002903 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002904 // xmm_scratch = 0.5
2905 ExternalReference one_half = ExternalReference::address_of_one_half();
2906 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
2907
danno@chromium.org160a7b02011-04-18 15:51:38 +00002908 __ ucomisd(xmm_scratch, input_reg);
2909 __ j(above, &below_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002910 // input = input + 0.5
2911 __ addsd(input_reg, xmm_scratch);
2912
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002913
2914 // Compute Math.floor(value + 0.5).
2915 // Use truncating instruction (OK because input is positive).
2916 __ cvttsd2si(output_reg, Operand(input_reg));
2917
2918 // Overflow is signalled with minint.
2919 __ cmp(output_reg, 0x80000000u);
2920 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002921 __ jmp(&done);
2922
2923 __ bind(&below_half);
2924
2925 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
2926 // we can ignore the difference between a result of -0 and +0.
2927 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2928 // If the sign is positive, we return +0.
2929 __ movmskpd(output_reg, input_reg);
2930 __ test(output_reg, Immediate(1));
2931 DeoptimizeIf(not_zero, instr->environment());
2932 } else {
2933 // If the input is >= -0.5, we return +0.
2934 __ mov(output_reg, Immediate(0xBF000000));
2935 __ movd(xmm_scratch, Operand(output_reg));
2936 __ cvtss2sd(xmm_scratch, xmm_scratch);
2937 __ ucomisd(input_reg, xmm_scratch);
2938 DeoptimizeIf(below, instr->environment());
2939 }
2940 __ Set(output_reg, Immediate(0));
2941 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002942}
2943
2944
2945void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002946 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002947 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2948 __ sqrtsd(input_reg, input_reg);
2949}
2950
2951
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002952void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2953 XMMRegister xmm_scratch = xmm0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002954 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002955 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002956 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002957 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002958 __ sqrtsd(input_reg, input_reg);
2959}
2960
2961
2962void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002963 LOperand* left = instr->InputAt(0);
2964 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002965 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2966 Representation exponent_type = instr->hydrogen()->right()->representation();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002967
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002968 if (exponent_type.IsDouble()) {
2969 // It is safe to use ebx directly since the instruction is marked
2970 // as a call.
2971 __ PrepareCallCFunction(4, ebx);
2972 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2973 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2975 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002976 } else if (exponent_type.IsInteger32()) {
2977 // It is safe to use ebx directly since the instruction is marked
2978 // as a call.
2979 ASSERT(!ToRegister(right).is(ebx));
2980 __ PrepareCallCFunction(4, ebx);
2981 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2982 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002983 __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
2984 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002985 } else {
2986 ASSERT(exponent_type.IsTagged());
2987 CpuFeatures::Scope scope(SSE2);
2988 Register right_reg = ToRegister(right);
2989
2990 Label non_smi, call;
2991 __ test(right_reg, Immediate(kSmiTagMask));
2992 __ j(not_zero, &non_smi);
2993 __ SmiUntag(right_reg);
2994 __ cvtsi2sd(result_reg, Operand(right_reg));
2995 __ jmp(&call);
2996
2997 __ bind(&non_smi);
2998 // It is safe to use ebx directly since the instruction is marked
2999 // as a call.
3000 ASSERT(!right_reg.is(ebx));
3001 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
3002 DeoptimizeIf(not_equal, instr->environment());
3003 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
3004
3005 __ bind(&call);
3006 __ PrepareCallCFunction(4, ebx);
3007 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
3008 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003009 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
3010 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003011 }
3012
3013 // Return value is in st(0) on ia32.
3014 // Store it into the (fixed) result register.
3015 __ sub(Operand(esp), Immediate(kDoubleSize));
3016 __ fstp_d(Operand(esp, 0));
3017 __ movdbl(result_reg, Operand(esp, 0));
3018 __ add(Operand(esp), Immediate(kDoubleSize));
3019}
3020
3021
3022void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003023 ASSERT(instr->InputAt(0)->Equals(instr->result()));
3024 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003025 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003026 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003027 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003028 __ j(above, &positive, Label::kNear);
3029 __ j(equal, &zero, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003030 ExternalReference nan = ExternalReference::address_of_nan();
3031 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003032 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003033 __ bind(&zero);
3034 __ push(Immediate(0xFFF00000));
3035 __ push(Immediate(0));
3036 __ movdbl(input_reg, Operand(esp, 0));
3037 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003038 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003039 __ bind(&positive);
3040 __ fldln2();
3041 __ sub(Operand(esp), Immediate(kDoubleSize));
3042 __ movdbl(Operand(esp, 0), input_reg);
3043 __ fld_d(Operand(esp, 0));
3044 __ fyl2x();
3045 __ fstp_d(Operand(esp, 0));
3046 __ movdbl(input_reg, Operand(esp, 0));
3047 __ add(Operand(esp), Immediate(kDoubleSize));
3048 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003049}
3050
3051
3052void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3053 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3054 TranscendentalCacheStub stub(TranscendentalCache::COS,
3055 TranscendentalCacheStub::UNTAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003056 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003057}
3058
3059
3060void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3061 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3062 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3063 TranscendentalCacheStub::UNTAGGED);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003064 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003065}
3066
3067
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003068void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3069 switch (instr->op()) {
3070 case kMathAbs:
3071 DoMathAbs(instr);
3072 break;
3073 case kMathFloor:
3074 DoMathFloor(instr);
3075 break;
3076 case kMathRound:
3077 DoMathRound(instr);
3078 break;
3079 case kMathSqrt:
3080 DoMathSqrt(instr);
3081 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003082 case kMathPowHalf:
3083 DoMathPowHalf(instr);
3084 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003085 case kMathCos:
3086 DoMathCos(instr);
3087 break;
3088 case kMathSin:
3089 DoMathSin(instr);
3090 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003091 case kMathLog:
3092 DoMathLog(instr);
3093 break;
3094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095 default:
3096 UNREACHABLE();
3097 }
3098}
3099
3100
danno@chromium.org160a7b02011-04-18 15:51:38 +00003101void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3102 ASSERT(ToRegister(instr->context()).is(esi));
3103 ASSERT(ToRegister(instr->function()).is(edi));
3104 ASSERT(instr->HasPointerMap());
3105 ASSERT(instr->HasDeoptimizationEnvironment());
3106 LPointerMap* pointers = instr->pointer_map();
3107 LEnvironment* env = instr->deoptimization_environment();
3108 RecordPosition(pointers->position());
3109 RegisterEnvironmentForDeoptimization(env);
3110 SafepointGenerator generator(this, pointers, env->deoptimization_index());
3111 ParameterCount count(instr->arity());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003112 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003113}
3114
3115
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003116void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003117 ASSERT(ToRegister(instr->context()).is(esi));
3118 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003119 ASSERT(ToRegister(instr->result()).is(eax));
3120
3121 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 Handle<Code> ic = isolate()->stub_cache()->
3123 ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003124 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003125}
3126
3127
3128void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003129 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003130 ASSERT(ToRegister(instr->result()).is(eax));
3131
3132 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003133 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3134 Handle<Code> ic =
3135 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003136 __ mov(ecx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003137 CallCode(ic, mode, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003138}
3139
3140
3141void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003142 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003143 ASSERT(ToRegister(instr->result()).is(eax));
3144
3145 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003146 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003147 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003148 __ Drop(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003149}
3150
3151
3152void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003153 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003154 ASSERT(ToRegister(instr->result()).is(eax));
3155
3156 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003157 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3158 Handle<Code> ic =
3159 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003160 __ mov(ecx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003161 CallCode(ic, mode, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003162}
3163
3164
3165void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3166 ASSERT(ToRegister(instr->result()).is(eax));
3167 __ mov(edi, instr->target());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003168 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003169}
3170
3171
3172void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003173 ASSERT(ToRegister(instr->context()).is(esi));
3174 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003175 ASSERT(ToRegister(instr->result()).is(eax));
3176
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003177 Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003178 __ Set(eax, Immediate(instr->arity()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003179 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003180}
3181
3182
3183void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003184 CallRuntime(instr->function(), instr->arity(), instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003185}
3186
3187
3188void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3189 Register object = ToRegister(instr->object());
3190 Register value = ToRegister(instr->value());
3191 int offset = instr->offset();
3192
3193 if (!instr->transition().is_null()) {
3194 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3195 }
3196
3197 // Do the store.
3198 if (instr->is_in_object()) {
3199 __ mov(FieldOperand(object, offset), value);
3200 if (instr->needs_write_barrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003201 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003202 // Update the write barrier for the object for in-object properties.
3203 __ RecordWrite(object, offset, value, temp);
3204 }
3205 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003206 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003207 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3208 __ mov(FieldOperand(temp, offset), value);
3209 if (instr->needs_write_barrier()) {
3210 // Update the write barrier for the properties array.
3211 // object is used as a scratch register.
3212 __ RecordWrite(temp, offset, value, object);
3213 }
3214 }
3215}
3216
3217
3218void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003219 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003220 ASSERT(ToRegister(instr->object()).is(edx));
3221 ASSERT(ToRegister(instr->value()).is(eax));
3222
3223 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003224 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003225 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3226 : isolate()->builtins()->StoreIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003227 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003228}
3229
3230
3231void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
3232 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3233 DeoptimizeIf(above_equal, instr->environment());
3234}
3235
3236
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003237void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3238 LStoreKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003239 ExternalArrayType array_type = instr->array_type();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003240 Operand operand(BuildExternalArrayOperand(instr->external_pointer(),
3241 instr->key(), array_type));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003242 if (array_type == kExternalFloatArray) {
3243 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003244 __ movss(operand, xmm0);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003245 } else if (array_type == kExternalDoubleArray) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003246 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003247 } else {
3248 Register value = ToRegister(instr->value());
3249 switch (array_type) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00003250 case kExternalPixelArray:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003251 case kExternalByteArray:
3252 case kExternalUnsignedByteArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003253 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003254 break;
3255 case kExternalShortArray:
3256 case kExternalUnsignedShortArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003257 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003258 break;
3259 case kExternalIntArray:
3260 case kExternalUnsignedIntArray:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003261 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003262 break;
3263 case kExternalFloatArray:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003264 case kExternalDoubleArray:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003265 UNREACHABLE();
3266 break;
3267 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003268 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003269}
3270
3271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003272void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3273 Register value = ToRegister(instr->value());
3274 Register elements = ToRegister(instr->object());
3275 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3276
3277 // Do the store.
3278 if (instr->key()->IsConstantOperand()) {
3279 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3280 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3281 int offset =
3282 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3283 __ mov(FieldOperand(elements, offset), value);
3284 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003285 __ mov(FieldOperand(elements,
3286 key,
3287 times_pointer_size,
3288 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003289 value);
3290 }
3291
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003292 if (instr->hydrogen()->NeedsWriteBarrier()) {
3293 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003294 __ lea(key,
3295 FieldOperand(elements,
3296 key,
3297 times_pointer_size,
3298 FixedArray::kHeaderSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003299 __ RecordWrite(elements, key, value);
3300 }
3301}
3302
3303
3304void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003305 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003306 ASSERT(ToRegister(instr->object()).is(edx));
3307 ASSERT(ToRegister(instr->key()).is(ecx));
3308 ASSERT(ToRegister(instr->value()).is(eax));
3309
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003310 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003311 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3312 : isolate()->builtins()->KeyedStoreIC_Initialize();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003313 CallCode(ic, RelocInfo::CODE_TARGET, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003314}
3315
3316
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003317void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3318 class DeferredStringCharCodeAt: public LDeferredCode {
3319 public:
3320 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3321 : LDeferredCode(codegen), instr_(instr) { }
3322 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
3323 private:
3324 LStringCharCodeAt* instr_;
3325 };
3326
3327 Register string = ToRegister(instr->string());
3328 Register index = no_reg;
3329 int const_index = -1;
3330 if (instr->index()->IsConstantOperand()) {
3331 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3332 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3333 if (!Smi::IsValid(const_index)) {
3334 // Guaranteed to be out of bounds because of the assert above.
3335 // So the bounds check that must dominate this instruction must
3336 // have deoptimized already.
3337 if (FLAG_debug_code) {
3338 __ Abort("StringCharCodeAt: out of bounds index.");
3339 }
3340 // No code needs to be generated.
3341 return;
3342 }
3343 } else {
3344 index = ToRegister(instr->index());
3345 }
3346 Register result = ToRegister(instr->result());
3347
3348 DeferredStringCharCodeAt* deferred =
3349 new DeferredStringCharCodeAt(this, instr);
3350
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003351 Label flat_string, ascii_string, done;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003352
3353 // Fetch the instance type of the receiver into result register.
3354 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3355 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3356
3357 // We need special handling for non-flat strings.
3358 STATIC_ASSERT(kSeqStringTag == 0);
3359 __ test(result, Immediate(kStringRepresentationMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003360 __ j(zero, &flat_string, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003361
3362 // Handle non-flat strings.
3363 __ test(result, Immediate(kIsConsStringMask));
3364 __ j(zero, deferred->entry());
3365
3366 // ConsString.
3367 // Check whether the right hand side is the empty string (i.e. if
3368 // this is really a flat string in a cons string). If that is not
3369 // the case we would rather go to the runtime system now to flatten
3370 // the string.
3371 __ cmp(FieldOperand(string, ConsString::kSecondOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003372 Immediate(factory()->empty_string()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003373 __ j(not_equal, deferred->entry());
3374 // Get the first of the two strings and load its instance type.
3375 __ mov(string, FieldOperand(string, ConsString::kFirstOffset));
3376 __ mov(result, FieldOperand(string, HeapObject::kMapOffset));
3377 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset));
3378 // If the first cons component is also non-flat, then go to runtime.
3379 STATIC_ASSERT(kSeqStringTag == 0);
3380 __ test(result, Immediate(kStringRepresentationMask));
3381 __ j(not_zero, deferred->entry());
3382
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003383 // Check for ASCII or two-byte string.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003384 __ bind(&flat_string);
3385 STATIC_ASSERT(kAsciiStringTag != 0);
3386 __ test(result, Immediate(kStringEncodingMask));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003387 __ j(not_zero, &ascii_string, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003388
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003389 // Two-byte string.
3390 // Load the two-byte character code into the result register.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003391 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3392 if (instr->index()->IsConstantOperand()) {
3393 __ movzx_w(result,
3394 FieldOperand(string,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003395 SeqTwoByteString::kHeaderSize +
3396 (kUC16Size * const_index)));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003397 } else {
3398 __ movzx_w(result, FieldOperand(string,
3399 index,
3400 times_2,
3401 SeqTwoByteString::kHeaderSize));
3402 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003403 __ jmp(&done, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003404
3405 // ASCII string.
3406 // Load the byte into the result register.
3407 __ bind(&ascii_string);
3408 if (instr->index()->IsConstantOperand()) {
3409 __ movzx_b(result, FieldOperand(string,
3410 SeqAsciiString::kHeaderSize + const_index));
3411 } else {
3412 __ movzx_b(result, FieldOperand(string,
3413 index,
3414 times_1,
3415 SeqAsciiString::kHeaderSize));
3416 }
3417 __ bind(&done);
3418 __ bind(deferred->exit());
3419}
3420
3421
3422void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3423 Register string = ToRegister(instr->string());
3424 Register result = ToRegister(instr->result());
3425
3426 // TODO(3095996): Get rid of this. For now, we need to make the
3427 // result register contain a valid pointer because it is already
3428 // contained in the register pointer map.
3429 __ Set(result, Immediate(0));
3430
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003431 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003432 __ push(string);
3433 // Push the index as a smi. This is safe because of the checks in
3434 // DoStringCharCodeAt above.
3435 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3436 if (instr->index()->IsConstantOperand()) {
3437 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3438 __ push(Immediate(Smi::FromInt(const_index)));
3439 } else {
3440 Register index = ToRegister(instr->index());
3441 __ SmiTag(index);
3442 __ push(index);
3443 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003444 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003445 if (FLAG_debug_code) {
3446 __ AbortIfNotSmi(eax);
3447 }
3448 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003449 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003450}
3451
3452
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003453void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3454 class DeferredStringCharFromCode: public LDeferredCode {
3455 public:
3456 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3457 : LDeferredCode(codegen), instr_(instr) { }
3458 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
3459 private:
3460 LStringCharFromCode* instr_;
3461 };
3462
3463 DeferredStringCharFromCode* deferred =
3464 new DeferredStringCharFromCode(this, instr);
3465
3466 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3467 Register char_code = ToRegister(instr->char_code());
3468 Register result = ToRegister(instr->result());
3469 ASSERT(!char_code.is(result));
3470
3471 __ cmp(char_code, String::kMaxAsciiCharCode);
3472 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003473 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003474 __ mov(result, FieldOperand(result,
3475 char_code, times_pointer_size,
3476 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003477 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003478 __ j(equal, deferred->entry());
3479 __ bind(deferred->exit());
3480}
3481
3482
3483void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3484 Register char_code = ToRegister(instr->char_code());
3485 Register result = ToRegister(instr->result());
3486
3487 // TODO(3095996): Get rid of this. For now, we need to make the
3488 // result register contain a valid pointer because it is already
3489 // contained in the register pointer map.
3490 __ Set(result, Immediate(0));
3491
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003492 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003493 __ SmiTag(char_code);
3494 __ push(char_code);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003495 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003496 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003497}
3498
3499
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003500void LCodeGen::DoStringLength(LStringLength* instr) {
3501 Register string = ToRegister(instr->string());
3502 Register result = ToRegister(instr->result());
3503 __ mov(result, FieldOperand(string, String::kLengthOffset));
3504}
3505
3506
danno@chromium.org160a7b02011-04-18 15:51:38 +00003507void LCodeGen::DoStringAdd(LStringAdd* instr) {
3508 if (instr->left()->IsConstantOperand()) {
3509 __ push(ToImmediate(instr->left()));
3510 } else {
3511 __ push(ToOperand(instr->left()));
3512 }
3513 if (instr->right()->IsConstantOperand()) {
3514 __ push(ToImmediate(instr->right()));
3515 } else {
3516 __ push(ToOperand(instr->right()));
3517 }
3518 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
3519 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
3520}
3521
3522
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003523void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003524 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003525 ASSERT(input->IsRegister() || input->IsStackSlot());
3526 LOperand* output = instr->result();
3527 ASSERT(output->IsDoubleRegister());
3528 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3529}
3530
3531
3532void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3533 class DeferredNumberTagI: public LDeferredCode {
3534 public:
3535 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3536 : LDeferredCode(codegen), instr_(instr) { }
3537 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
3538 private:
3539 LNumberTagI* instr_;
3540 };
3541
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003542 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003543 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3544 Register reg = ToRegister(input);
3545
3546 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3547 __ SmiTag(reg);
3548 __ j(overflow, deferred->entry());
3549 __ bind(deferred->exit());
3550}
3551
3552
3553void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3554 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003555 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003556 Register tmp = reg.is(eax) ? ecx : eax;
3557
3558 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003559 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003560
3561 // There was overflow, so bits 30 and 31 of the original integer
3562 // disagree. Try to allocate a heap number in new space and store
3563 // the value in there. If that fails, call the runtime system.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003564 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003565 __ SmiUntag(reg);
3566 __ xor_(reg, 0x80000000);
3567 __ cvtsi2sd(xmm0, Operand(reg));
3568 if (FLAG_inline_new) {
3569 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003570 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003571 }
3572
3573 // Slow case: Call the runtime system to do the number allocation.
3574 __ bind(&slow);
3575
3576 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3577 // register is stored, as this register is in the pointer map, but contains an
3578 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003579 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003580
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003581 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003582 if (!reg.is(eax)) __ mov(reg, eax);
3583
3584 // Done. Put the value in xmm0 into the value of the allocated heap
3585 // number.
3586 __ bind(&done);
3587 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003588 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003589}
3590
3591
3592void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3593 class DeferredNumberTagD: public LDeferredCode {
3594 public:
3595 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3596 : LDeferredCode(codegen), instr_(instr) { }
3597 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
3598 private:
3599 LNumberTagD* instr_;
3600 };
3601
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003602 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003604 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003605
3606 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3607 if (FLAG_inline_new) {
3608 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3609 } else {
3610 __ jmp(deferred->entry());
3611 }
3612 __ bind(deferred->exit());
3613 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3614}
3615
3616
3617void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3618 // TODO(3095996): Get rid of this. For now, we need to make the
3619 // result register contain a valid pointer because it is already
3620 // contained in the register pointer map.
3621 Register reg = ToRegister(instr->result());
3622 __ Set(reg, Immediate(0));
3623
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003624 PushSafepointRegistersScope scope(this);
3625 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003626 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003627}
3628
3629
3630void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003631 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003632 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3633 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3634 __ SmiTag(ToRegister(input));
3635}
3636
3637
3638void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003639 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003640 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3641 if (instr->needs_check()) {
3642 __ test(ToRegister(input), Immediate(kSmiTagMask));
3643 DeoptimizeIf(not_zero, instr->environment());
3644 }
3645 __ SmiUntag(ToRegister(input));
3646}
3647
3648
3649void LCodeGen::EmitNumberUntagD(Register input_reg,
3650 XMMRegister result_reg,
3651 LEnvironment* env) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003652 Label load_smi, heap_number, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003653
3654 // Smi check.
3655 __ test(input_reg, Immediate(kSmiTagMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003656 __ j(zero, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003657
3658 // Heap number map check.
3659 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 factory()->heap_number_map());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003661 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003662
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003664 DeoptimizeIf(not_equal, env);
3665
3666 // Convert undefined to NaN.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 ExternalReference nan = ExternalReference::address_of_nan();
3668 __ movdbl(result_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003669 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003670
3671 // Heap number to XMM conversion.
3672 __ bind(&heap_number);
3673 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003674 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003675
3676 // Smi to XMM conversion
3677 __ bind(&load_smi);
3678 __ SmiUntag(input_reg); // Untag smi before converting to float.
3679 __ cvtsi2sd(result_reg, Operand(input_reg));
3680 __ SmiTag(input_reg); // Retag smi.
3681 __ bind(&done);
3682}
3683
3684
3685class DeferredTaggedToI: public LDeferredCode {
3686 public:
3687 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3688 : LDeferredCode(codegen), instr_(instr) { }
3689 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3690 private:
3691 LTaggedToI* instr_;
3692};
3693
3694
3695void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003696 Label done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003697 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003698
3699 // Heap number map check.
3700 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003702
3703 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003704 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003705 // Check for undefined. Undefined is converted to zero for truncating
3706 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003708 DeoptimizeIf(not_equal, instr->environment());
3709 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003710 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003711
3712 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003713 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003714 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003715 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003716 // Use more powerful conversion when sse3 is available.
3717 // Load x87 register with heap number.
3718 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3719 // Get exponent alone and check for too-big exponent.
3720 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3721 __ and_(input_reg, HeapNumber::kExponentMask);
3722 const uint32_t kTooBigExponent =
3723 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3724 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003725 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003726 // Pop FPU stack before deoptimizing.
3727 __ ffree(0);
3728 __ fincstp();
3729 DeoptimizeIf(no_condition, instr->environment());
3730
3731 // Reserve space for 64 bit answer.
3732 __ bind(&convert);
3733 __ sub(Operand(esp), Immediate(kDoubleSize));
3734 // Do conversion, which cannot fail because we checked the exponent.
3735 __ fisttp_d(Operand(esp, 0));
3736 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3737 __ add(Operand(esp), Immediate(kDoubleSize));
3738 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003739 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003740 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3741 __ cvttsd2si(input_reg, Operand(xmm0));
3742 __ cmp(input_reg, 0x80000000u);
3743 __ j(not_equal, &done);
3744 // Check if the input was 0x8000000 (kMinInt).
3745 // If no, then we got an overflow and we deoptimize.
3746 ExternalReference min_int = ExternalReference::address_of_min_int();
3747 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3748 __ ucomisd(xmm_temp, xmm0);
3749 DeoptimizeIf(not_equal, instr->environment());
3750 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3751 }
3752 } else {
3753 // Deoptimize if we don't have a heap number.
3754 DeoptimizeIf(not_equal, instr->environment());
3755
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003756 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003757 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3758 __ cvttsd2si(input_reg, Operand(xmm0));
3759 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3760 __ ucomisd(xmm0, xmm_temp);
3761 DeoptimizeIf(not_equal, instr->environment());
3762 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3763 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3764 __ test(input_reg, Operand(input_reg));
3765 __ j(not_zero, &done);
3766 __ movmskpd(input_reg, xmm0);
3767 __ and_(input_reg, 1);
3768 DeoptimizeIf(not_zero, instr->environment());
3769 }
3770 }
3771 __ bind(&done);
3772}
3773
3774
3775void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003776 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003777 ASSERT(input->IsRegister());
3778 ASSERT(input->Equals(instr->result()));
3779
3780 Register input_reg = ToRegister(input);
3781
3782 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3783
3784 // Smi check.
3785 __ test(input_reg, Immediate(kSmiTagMask));
3786 __ j(not_zero, deferred->entry());
3787
3788 // Smi to int32 conversion
3789 __ SmiUntag(input_reg); // Untag smi.
3790
3791 __ bind(deferred->exit());
3792}
3793
3794
3795void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003796 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003797 ASSERT(input->IsRegister());
3798 LOperand* result = instr->result();
3799 ASSERT(result->IsDoubleRegister());
3800
3801 Register input_reg = ToRegister(input);
3802 XMMRegister result_reg = ToDoubleRegister(result);
3803
3804 EmitNumberUntagD(input_reg, result_reg, instr->environment());
3805}
3806
3807
3808void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003809 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003810 ASSERT(input->IsDoubleRegister());
3811 LOperand* result = instr->result();
3812 ASSERT(result->IsRegister());
3813
3814 XMMRegister input_reg = ToDoubleRegister(input);
3815 Register result_reg = ToRegister(result);
3816
3817 if (instr->truncating()) {
3818 // Performs a truncating conversion of a floating point number as used by
3819 // the JS bitwise operations.
3820 __ cvttsd2si(result_reg, Operand(input_reg));
3821 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003822 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003823 // This will deoptimize if the exponent of the input in out of range.
3824 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003825 Label convert, done;
3826 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003827 __ sub(Operand(esp), Immediate(kDoubleSize));
3828 __ movdbl(Operand(esp, 0), input_reg);
3829 // Get exponent alone and check for too-big exponent.
3830 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3831 __ and_(result_reg, HeapNumber::kExponentMask);
3832 const uint32_t kTooBigExponent =
3833 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3834 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003835 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003836 __ add(Operand(esp), Immediate(kDoubleSize));
3837 DeoptimizeIf(no_condition, instr->environment());
3838 __ bind(&convert);
3839 // Do conversion, which cannot fail because we checked the exponent.
3840 __ fld_d(Operand(esp, 0));
3841 __ fisttp_d(Operand(esp, 0));
3842 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3843 __ add(Operand(esp), Immediate(kDoubleSize));
3844 __ bind(&done);
3845 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003846 Label done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003847 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003848 XMMRegister xmm_scratch = xmm0;
3849
3850 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3851 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003852 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003853
3854 // Get high 32 bits of the input in result_reg and temp_reg.
3855 __ pshufd(xmm_scratch, input_reg, 1);
3856 __ movd(Operand(temp_reg), xmm_scratch);
3857 __ mov(result_reg, temp_reg);
3858
3859 // Prepare negation mask in temp_reg.
3860 __ sar(temp_reg, kBitsPerInt - 1);
3861
3862 // Extract the exponent from result_reg and subtract adjusted
3863 // bias from it. The adjustment is selected in a way such that
3864 // when the difference is zero, the answer is in the low 32 bits
3865 // of the input, otherwise a shift has to be performed.
3866 __ shr(result_reg, HeapNumber::kExponentShift);
3867 __ and_(result_reg,
3868 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3869 __ sub(Operand(result_reg),
3870 Immediate(HeapNumber::kExponentBias +
3871 HeapNumber::kExponentBits +
3872 HeapNumber::kMantissaBits));
3873 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3874 // special exponents.
3875 DeoptimizeIf(greater, instr->environment());
3876
3877 // Zero out the sign and the exponent in the input (by shifting
3878 // it to the left) and restore the implicit mantissa bit,
3879 // i.e. convert the input to unsigned int64 shifted left by
3880 // kExponentBits.
3881 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3882 // Minus zero has the most significant bit set and the other
3883 // bits cleared.
3884 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3885 __ psllq(input_reg, HeapNumber::kExponentBits);
3886 __ por(input_reg, xmm_scratch);
3887
3888 // Get the amount to shift the input right in xmm_scratch.
3889 __ neg(result_reg);
3890 __ movd(xmm_scratch, Operand(result_reg));
3891
3892 // Shift the input right and extract low 32 bits.
3893 __ psrlq(input_reg, xmm_scratch);
3894 __ movd(Operand(result_reg), input_reg);
3895
3896 // Use the prepared mask in temp_reg to negate the result if necessary.
3897 __ xor_(result_reg, Operand(temp_reg));
3898 __ sub(result_reg, Operand(temp_reg));
3899 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003900 }
3901 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003902 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003903 __ cvttsd2si(result_reg, Operand(input_reg));
3904 __ cvtsi2sd(xmm0, Operand(result_reg));
3905 __ ucomisd(xmm0, input_reg);
3906 DeoptimizeIf(not_equal, instr->environment());
3907 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3908 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3909 // The integer converted back is equal to the original. We
3910 // only have to test if we got -0 as an input.
3911 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003912 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003913 __ movmskpd(result_reg, input_reg);
3914 // Bit 0 contains the sign of the double in input_reg.
3915 // If input was positive, we are ok and return 0, otherwise
3916 // deoptimize.
3917 __ and_(result_reg, 1);
3918 DeoptimizeIf(not_zero, instr->environment());
3919 }
3920 __ bind(&done);
3921 }
3922}
3923
3924
3925void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003926 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003927 __ test(ToRegister(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003928 DeoptimizeIf(not_zero, instr->environment());
3929}
3930
3931
3932void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
3933 LOperand* input = instr->InputAt(0);
3934 __ test(ToRegister(input), Immediate(kSmiTagMask));
3935 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003936}
3937
3938
3939void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003940 Register input = ToRegister(instr->InputAt(0));
3941 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003942
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003943 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003944
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003945 if (instr->hydrogen()->is_interval_check()) {
3946 InstanceType first;
3947 InstanceType last;
3948 instr->hydrogen()->GetCheckInterval(&first, &last);
3949
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003950 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3951 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003952
3953 // If there is only one type in the interval check for equality.
3954 if (first == last) {
3955 DeoptimizeIf(not_equal, instr->environment());
3956 } else {
3957 DeoptimizeIf(below, instr->environment());
3958 // Omit check for the last type.
3959 if (last != LAST_TYPE) {
3960 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3961 static_cast<int8_t>(last));
3962 DeoptimizeIf(above, instr->environment());
3963 }
3964 }
3965 } else {
3966 uint8_t mask;
3967 uint8_t tag;
3968 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
3969
3970 if (IsPowerOf2(mask)) {
3971 ASSERT(tag == 0 || IsPowerOf2(tag));
3972 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
3973 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
3974 } else {
3975 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
3976 __ and_(temp, mask);
3977 __ cmpb(Operand(temp), tag);
3978 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003979 }
3980 }
3981}
3982
3983
3984void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003985 ASSERT(instr->InputAt(0)->IsRegister());
3986 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003987 __ cmp(reg, instr->hydrogen()->target());
3988 DeoptimizeIf(not_equal, instr->environment());
3989}
3990
3991
3992void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003993 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003994 ASSERT(input->IsRegister());
3995 Register reg = ToRegister(input);
3996 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
3997 instr->hydrogen()->map());
3998 DeoptimizeIf(not_equal, instr->environment());
3999}
4000
4001
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004002void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4003 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4004 Register result_reg = ToRegister(instr->result());
4005 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4006}
4007
4008
4009void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4010 ASSERT(instr->unclamped()->Equals(instr->result()));
4011 Register value_reg = ToRegister(instr->result());
4012 __ ClampUint8(value_reg);
4013}
4014
4015
4016void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4017 ASSERT(instr->unclamped()->Equals(instr->result()));
4018 Register input_reg = ToRegister(instr->unclamped());
4019 Label is_smi, done, heap_number;
4020
4021 __ JumpIfSmi(input_reg, &is_smi);
4022
4023 // Check for heap number
4024 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4025 factory()->heap_number_map());
4026 __ j(equal, &heap_number, Label::kNear);
4027
4028 // Check for undefined. Undefined is converted to zero for clamping
4029 // conversions.
4030 __ cmp(input_reg, factory()->undefined_value());
4031 DeoptimizeIf(not_equal, instr->environment());
4032 __ mov(input_reg, 0);
4033 __ jmp(&done, Label::kNear);
4034
4035 // Heap number
4036 __ bind(&heap_number);
4037 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4038 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4039 __ jmp(&done, Label::kNear);
4040
4041 // smi
4042 __ bind(&is_smi);
4043 __ SmiUntag(input_reg);
4044 __ ClampUint8(input_reg);
4045
4046 __ bind(&done);
4047}
4048
4049
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004050void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004051 if (isolate()->heap()->InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004052 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053 isolate()->factory()->NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004054 __ mov(result, Operand::Cell(cell));
4055 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004056 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004057 }
4058}
4059
4060
4061void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004062 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004063
4064 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004065 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004066
4067 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004068 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004069
4070 // Check prototype maps up to the holder.
4071 while (!current_prototype.is_identical_to(holder)) {
4072 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
4073 Handle<Map>(current_prototype->map()));
4074 DeoptimizeIf(not_equal, instr->environment());
4075 current_prototype =
4076 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4077 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004078 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004079 }
4080
4081 // Check the holder map.
4082 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
4083 Handle<Map>(current_prototype->map()));
4084 DeoptimizeIf(not_equal, instr->environment());
4085}
4086
4087
4088void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
4089 // Setup the parameters to the stub/runtime call.
4090 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4091 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
4092 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
4093 __ push(Immediate(instr->hydrogen()->constant_elements()));
4094
4095 // Pick the right runtime function or stub to call.
4096 int length = instr->hydrogen()->length();
4097 if (instr->hydrogen()->IsCopyOnWrite()) {
4098 ASSERT(instr->hydrogen()->depth() == 1);
4099 FastCloneShallowArrayStub::Mode mode =
4100 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4101 FastCloneShallowArrayStub stub(mode, length);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004102 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004103 } else if (instr->hydrogen()->depth() > 1) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004104 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004105 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004106 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004107 } else {
4108 FastCloneShallowArrayStub::Mode mode =
4109 FastCloneShallowArrayStub::CLONE_ELEMENTS;
4110 FastCloneShallowArrayStub stub(mode, length);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004111 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004112 }
4113}
4114
4115
4116void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004117 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004118 // Setup the parameters to the stub/runtime call.
4119 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4120 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
4121 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
4122 __ push(Immediate(instr->hydrogen()->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004123 int flags = instr->hydrogen()->fast_elements()
4124 ? ObjectLiteral::kFastElements
4125 : ObjectLiteral::kNoFlags;
4126 flags |= instr->hydrogen()->has_function()
4127 ? ObjectLiteral::kHasFunction
4128 : ObjectLiteral::kNoFlags;
4129 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004130
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004131 // Pick the right runtime function to call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004132 if (instr->hydrogen()->depth() > 1) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004133 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr, CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004134 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004135 CallRuntime(Runtime::kCreateObjectLiteralShallow,
4136 4,
4137 instr,
4138 CONTEXT_ADJUSTED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004139 }
4140}
4141
4142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
4144 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
4145 __ push(eax);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004146 CallRuntime(Runtime::kToFastProperties, 1, instr, CONTEXT_ADJUSTED);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147}
4148
4149
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004150void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004151 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004152 // Registers will be used as follows:
4153 // edi = JS function.
4154 // ecx = literals array.
4155 // ebx = regexp literal.
4156 // eax = regexp literal clone.
4157 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4158 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
4159 int literal_offset = FixedArray::kHeaderSize +
4160 instr->hydrogen()->literal_index() * kPointerSize;
4161 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004162 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004163 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004164
4165 // Create regexp literal using runtime function
4166 // Result will be in eax.
4167 __ push(ecx);
4168 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
4169 __ push(Immediate(instr->hydrogen()->pattern()));
4170 __ push(Immediate(instr->hydrogen()->flags()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004171 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004172 __ mov(ebx, eax);
4173
4174 __ bind(&materialized);
4175 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
4176 Label allocated, runtime_allocate;
4177 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
4178 __ jmp(&allocated);
4179
4180 __ bind(&runtime_allocate);
4181 __ push(ebx);
4182 __ push(Immediate(Smi::FromInt(size)));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004183 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004184 __ pop(ebx);
4185
4186 __ bind(&allocated);
4187 // Copy the content into the newly allocated memory.
4188 // (Unroll copy loop once for better throughput).
4189 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4190 __ mov(edx, FieldOperand(ebx, i));
4191 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
4192 __ mov(FieldOperand(eax, i), edx);
4193 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
4194 }
4195 if ((size % (2 * kPointerSize)) != 0) {
4196 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
4197 __ mov(FieldOperand(eax, size - kPointerSize), edx);
4198 }
4199}
4200
4201
4202void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
4203 // Use the fast case closure allocation code that allocates in new
4204 // space for nested functions that don't need literals cloning.
4205 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004206 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004207 if (!pretenure && shared_info->num_literals() == 0) {
4208 FastNewClosureStub stub(
4209 shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004210 __ push(Immediate(shared_info));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004211 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004212 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004213 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004214 __ push(Immediate(shared_info));
4215 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 ? factory()->true_value()
4217 : factory()->false_value()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004218 CallRuntime(Runtime::kNewClosure, 3, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004219 }
4220}
4221
4222
4223void LCodeGen::DoTypeof(LTypeof* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004224 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004225 if (input->IsConstantOperand()) {
4226 __ push(ToImmediate(input));
4227 } else {
4228 __ push(ToOperand(input));
4229 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004230 CallRuntime(Runtime::kTypeof, 1, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004231}
4232
4233
4234void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004235 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004236 Register result = ToRegister(instr->result());
4237 Label true_label;
4238 Label false_label;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004239 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004240
4241 Condition final_branch_condition = EmitTypeofIs(&true_label,
4242 &false_label,
4243 input,
4244 instr->type_literal());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004245 __ j(final_branch_condition, &true_label, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004246 __ bind(&false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247 __ mov(result, factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004248 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004249
4250 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004251 __ mov(result, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004252
4253 __ bind(&done);
4254}
4255
4256
4257void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004258 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004259 int true_block = chunk_->LookupDestination(instr->true_block_id());
4260 int false_block = chunk_->LookupDestination(instr->false_block_id());
4261 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4262 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4263
4264 Condition final_branch_condition = EmitTypeofIs(true_label,
4265 false_label,
4266 input,
4267 instr->type_literal());
4268
4269 EmitBranch(true_block, false_block, final_branch_condition);
4270}
4271
4272
4273Condition LCodeGen::EmitTypeofIs(Label* true_label,
4274 Label* false_label,
4275 Register input,
4276 Handle<String> type_name) {
4277 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004278 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004279 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004280 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004281 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004282 final_branch_condition = equal;
4283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004284 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004285 __ JumpIfSmi(input, false_label);
4286 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
4287 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004288 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4289 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004290 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004291
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 } else if (type_name->Equals(heap()->boolean_symbol())) {
4293 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004294 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004296 final_branch_condition = equal;
4297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 } else if (type_name->Equals(heap()->undefined_symbol())) {
4299 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004300 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004301 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004302 // Check for undetectable objects => true.
4303 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
4304 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4305 1 << Map::kIsUndetectable);
4306 final_branch_condition = not_zero;
4307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004308 } else if (type_name->Equals(heap()->function_symbol())) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004309 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004310 __ JumpIfSmi(input, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004311 __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004312 final_branch_condition = above_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004315 __ JumpIfSmi(input, false_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004316 __ cmp(input, factory()->null_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004317 __ j(equal, true_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004318 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004319 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004320 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4321 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004322 // Check for undetectable objects => false.
4323 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4324 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004325 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004326
4327 } else {
4328 final_branch_condition = not_equal;
4329 __ jmp(false_label);
4330 // A dead branch instruction will be generated after this point.
4331 }
4332
4333 return final_branch_condition;
4334}
4335
4336
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004337void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
4338 Register result = ToRegister(instr->result());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004339 Label true_label;
4340 Label done;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004341
4342 EmitIsConstructCall(result);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004343 __ j(equal, &true_label, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004345 __ mov(result, factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004346 __ jmp(&done, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004347
4348 __ bind(&true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004349 __ mov(result, factory()->true_value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004350
4351 __ bind(&done);
4352}
4353
4354
4355void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4356 Register temp = ToRegister(instr->TempAt(0));
4357 int true_block = chunk_->LookupDestination(instr->true_block_id());
4358 int false_block = chunk_->LookupDestination(instr->false_block_id());
4359
4360 EmitIsConstructCall(temp);
4361 EmitBranch(true_block, false_block, equal);
4362}
4363
4364
4365void LCodeGen::EmitIsConstructCall(Register temp) {
4366 // Get the frame pointer for the calling frame.
4367 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4368
4369 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004370 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004371 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4372 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004373 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004374 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
4375
4376 // Check the marker in the calling frame.
4377 __ bind(&check_frame_marker);
4378 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4379 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
4380}
4381
4382
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004383void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
4384 // No code for lazy bailout instruction. Used to capture environment after a
4385 // call for populating the safepoint data with deoptimization data.
4386}
4387
4388
4389void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4390 DeoptimizeIf(no_condition, instr->environment());
4391}
4392
4393
4394void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
4395 LOperand* obj = instr->object();
4396 LOperand* key = instr->key();
4397 __ push(ToOperand(obj));
4398 if (key->IsConstantOperand()) {
4399 __ push(ToImmediate(key));
4400 } else {
4401 __ push(ToOperand(key));
4402 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004403 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4404 LPointerMap* pointers = instr->pointer_map();
4405 LEnvironment* env = instr->deoptimization_environment();
4406 RecordPosition(pointers->position());
4407 RegisterEnvironmentForDeoptimization(env);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004408 // Create safepoint generator that will also ensure enough space in the
4409 // reloc info for patching in deoptimization (since this is invoking a
4410 // builtin)
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004411 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004412 pointers,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004413 env->deoptimization_index());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004414 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004415 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004416 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004417}
4418
4419
4420void LCodeGen::DoStackCheck(LStackCheck* instr) {
4421 // Perform stack overflow check.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004422 Label done;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 ExternalReference stack_limit =
4424 ExternalReference::address_of_stack_limit(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004425 __ cmp(esp, Operand::StaticVariable(stack_limit));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004426 __ j(above_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004427
4428 StackCheckStub stub;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004429 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, RESTORE_CONTEXT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004430 __ bind(&done);
4431}
4432
4433
4434void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
4435 // This is a pseudo-instruction that ensures that the environment here is
4436 // properly registered for deoptimization and records the assembler's PC
4437 // offset.
4438 LEnvironment* environment = instr->environment();
4439 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4440 instr->SpilledDoubleRegisterArray());
4441
4442 // If the environment were already registered, we would have no way of
4443 // backpatching it with the spill slot operands.
4444 ASSERT(!environment->HasBeenRegistered());
4445 RegisterEnvironmentForDeoptimization(environment);
4446 ASSERT(osr_pc_offset_ == -1);
4447 osr_pc_offset_ = masm()->pc_offset();
4448}
4449
4450
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004451void LCodeGen::DoIn(LIn* instr) {
4452 LOperand* obj = instr->object();
4453 LOperand* key = instr->key();
4454 if (key->IsConstantOperand()) {
4455 __ push(ToImmediate(key));
4456 } else {
4457 __ push(ToOperand(key));
4458 }
4459 if (obj->IsConstantOperand()) {
4460 __ push(ToImmediate(obj));
4461 } else {
4462 __ push(ToOperand(obj));
4463 }
4464 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4465 LPointerMap* pointers = instr->pointer_map();
4466 LEnvironment* env = instr->deoptimization_environment();
4467 RecordPosition(pointers->position());
4468 RegisterEnvironmentForDeoptimization(env);
4469 // Create safepoint generator that will also ensure enough space in the
4470 // reloc info for patching in deoptimization (since this is invoking a
4471 // builtin)
4472 SafepointGenerator safepoint_generator(this,
4473 pointers,
4474 env->deoptimization_index());
4475 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004476 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004477}
4478
4479
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004480#undef __
4481
4482} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004483
4484#endif // V8_TARGET_ARCH_IA32