blob: 7966e19fe35e1143a5812c57f9cb5204d0b653fb [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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"
erikcorry0ad885c2011-11-21 13:51:57 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037
38namespace v8 {
39namespace internal {
40
41
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000042// When invoking builtins, we need to record the safepoint in the middle of
43// the invoke instruction sequence generated by the macro assembler.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000044class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045 public:
46 SafepointGenerator(LCodeGen* codegen,
47 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000048 Safepoint::DeoptMode mode)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049 : codegen_(codegen),
50 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000051 deopt_mode_(mode) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052 virtual ~SafepointGenerator() { }
53
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054 virtual void BeforeCall(int call_size) const {}
55
56 virtual void AfterCall() const {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000057 codegen_->RecordSafepoint(pointers_, deopt_mode_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000058 }
59
60 private:
61 LCodeGen* codegen_;
62 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000063 Safepoint::DeoptMode deopt_mode_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000064};
65
66
67#define __ masm()->
68
69bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000070 HPhase phase("Z_Code generation", chunk());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000071 ASSERT(is_unused());
72 status_ = GENERATING;
73 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074
75 CodeStub::GenerateFPStubs();
76
77 // Open a frame scope to indicate that there is a frame on the stack. The
78 // MANUAL indicates that the scope shouldn't actually generate code to set up
79 // the frame (that is done in GeneratePrologue).
80 FrameScope frame_scope(masm_, StackFrame::MANUAL);
81
kasperl@chromium.orga5551262010-12-07 12:49:48 +000082 return GeneratePrologue() &&
83 GenerateBody() &&
84 GenerateDeferredCode() &&
85 GenerateSafepointTable();
86}
87
88
89void LCodeGen::FinishCode(Handle<Code> code) {
90 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000091 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000092 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000093 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000094 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000095}
96
97
98void LCodeGen::Abort(const char* format, ...) {
99 if (FLAG_trace_bailout) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000100 SmartArrayPointer<char> name(
101 info()->shared_info()->DebugName()->ToCString());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000102 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000103 va_list arguments;
104 va_start(arguments, format);
105 OS::VPrint(format, arguments);
106 va_end(arguments);
107 PrintF("\n");
108 }
109 status_ = ABORTED;
110}
111
112
113void LCodeGen::Comment(const char* format, ...) {
114 if (!FLAG_code_comments) return;
115 char buffer[4 * KB];
116 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
117 va_list arguments;
118 va_start(arguments, format);
119 builder.AddFormattedList(format, arguments);
120 va_end(arguments);
121
122 // Copy the string before recording it in the assembler to avoid
123 // issues when the stack allocated buffer goes out of scope.
124 size_t length = builder.position();
125 Vector<char> copy = Vector<char>::New(length + 1);
126 memcpy(copy.start(), builder.Finalize(), copy.length());
127 masm()->RecordComment(copy.start());
128}
129
130
131bool LCodeGen::GeneratePrologue() {
132 ASSERT(is_generating());
133
134#ifdef DEBUG
135 if (strlen(FLAG_stop_at) > 0 &&
136 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
137 __ int3();
138 }
139#endif
140
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000141 // Strict mode functions and builtins need to replace the receiver
142 // with undefined when called as functions (without an explicit
143 // receiver object). ecx is zero for method calls and non-zero for
144 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000145 if (!info_->is_classic_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000146 Label ok;
147 __ test(ecx, Operand(ecx));
148 __ j(zero, &ok, Label::kNear);
149 // +1 for return address.
150 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
151 __ mov(Operand(esp, receiver_offset),
152 Immediate(isolate()->factory()->undefined_value()));
153 __ bind(&ok);
154 }
155
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000156 __ push(ebp); // Caller's frame pointer.
157 __ mov(ebp, esp);
158 __ push(esi); // Callee's context.
159 __ push(edi); // Callee's JS function.
160
161 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000162 int slots = GetStackSlotCount();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000163 if (slots > 0) {
164 if (FLAG_debug_code) {
165 __ mov(Operand(eax), Immediate(slots));
166 Label loop;
167 __ bind(&loop);
168 __ push(Immediate(kSlotsZapValue));
169 __ dec(eax);
170 __ j(not_zero, &loop);
171 } else {
172 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000173#ifdef _MSC_VER
174 // On windows, you may not access the stack more than one page below
175 // the most recently mapped page. To make the allocated area randomly
176 // accessible, we write to each page in turn (the value is irrelevant).
177 const int kPageSize = 4 * KB;
178 for (int offset = slots * kPointerSize - kPageSize;
179 offset > 0;
180 offset -= kPageSize) {
181 __ mov(Operand(esp, offset), eax);
182 }
183#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000184 }
185 }
186
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000187 // Possibly allocate a local context.
188 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
189 if (heap_slots > 0) {
190 Comment(";;; Allocate local context");
191 // Argument to NewContext is the function, which is still in edi.
192 __ push(edi);
193 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
194 FastNewContextStub stub(heap_slots);
195 __ CallStub(&stub);
196 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000197 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000198 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000199 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000200 // Context is returned in both eax and esi. It replaces the context
201 // passed to us. It's saved in the stack and kept live in esi.
202 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
203
204 // Copy parameters into context if necessary.
205 int num_parameters = scope()->num_parameters();
206 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000207 Variable* var = scope()->parameter(i);
208 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000209 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
210 (num_parameters - 1 - i) * kPointerSize;
211 // Load parameter from stack.
212 __ mov(eax, Operand(ebp, parameter_offset));
213 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000214 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000215 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000216 // Update the write barrier. This clobbers eax and ebx.
217 __ RecordWriteContextSlot(esi,
218 context_offset,
219 eax,
220 ebx,
221 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000222 }
223 }
224 Comment(";;; End allocate local context");
225 }
226
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000227 // Trace the call.
228 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000229 // We have not executed any compiled code yet, so esi still holds the
230 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000231 __ CallRuntime(Runtime::kTraceEnter, 0);
232 }
233 return !is_aborted();
234}
235
236
237bool LCodeGen::GenerateBody() {
238 ASSERT(is_generating());
239 bool emit_instructions = true;
240 for (current_instruction_ = 0;
241 !is_aborted() && current_instruction_ < instructions_->length();
242 current_instruction_++) {
243 LInstruction* instr = instructions_->at(current_instruction_);
244 if (instr->IsLabel()) {
245 LLabel* label = LLabel::cast(instr);
246 emit_instructions = !label->HasReplacement();
247 }
248
249 if (emit_instructions) {
250 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
251 instr->CompileToNative(this);
252 }
253 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000254 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000255 return !is_aborted();
256}
257
258
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000259bool LCodeGen::GenerateDeferredCode() {
260 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000261 if (deferred_.length() > 0) {
262 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
263 LDeferredCode* code = deferred_[i];
264 __ bind(code->entry());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000265 Comment(";;; Deferred code @%d: %s.",
266 code->instruction_index(),
267 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000268 code->Generate();
269 __ jmp(code->exit());
270 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000271 }
272
273 // Deferred code is the last part of the instruction sequence. Mark
274 // the generated code as done unless we bailed out.
275 if (!is_aborted()) status_ = DONE;
276 return !is_aborted();
277}
278
279
280bool LCodeGen::GenerateSafepointTable() {
281 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000282 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000283 return !is_aborted();
284}
285
286
287Register LCodeGen::ToRegister(int index) const {
288 return Register::FromAllocationIndex(index);
289}
290
291
292XMMRegister LCodeGen::ToDoubleRegister(int index) const {
293 return XMMRegister::FromAllocationIndex(index);
294}
295
296
297Register LCodeGen::ToRegister(LOperand* op) const {
298 ASSERT(op->IsRegister());
299 return ToRegister(op->index());
300}
301
302
303XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
304 ASSERT(op->IsDoubleRegister());
305 return ToDoubleRegister(op->index());
306}
307
308
309int LCodeGen::ToInteger32(LConstantOperand* op) const {
310 Handle<Object> value = chunk_->LookupLiteral(op);
311 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
312 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
313 value->Number());
314 return static_cast<int32_t>(value->Number());
315}
316
317
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000318Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
319 Handle<Object> literal = chunk_->LookupLiteral(op);
320 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
321 return literal;
322}
323
324
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000325double LCodeGen::ToDouble(LConstantOperand* op) const {
326 Handle<Object> value = chunk_->LookupLiteral(op);
327 return value->Number();
328}
329
330
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000331bool LCodeGen::IsInteger32(LConstantOperand* op) const {
332 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000333}
334
335
336Operand LCodeGen::ToOperand(LOperand* op) const {
337 if (op->IsRegister()) return Operand(ToRegister(op));
338 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
339 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
340 int index = op->index();
341 if (index >= 0) {
342 // Local or spill slot. Skip the frame pointer, function, and
343 // context in the fixed part of the frame.
344 return Operand(ebp, -(index + 3) * kPointerSize);
345 } else {
346 // Incoming parameter. Skip the return address.
347 return Operand(ebp, -(index - 1) * kPointerSize);
348 }
349}
350
351
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000352Operand LCodeGen::HighOperand(LOperand* op) {
353 ASSERT(op->IsDoubleStackSlot());
354 int index = op->index();
355 int offset = (index >= 0) ? index + 3 : index - 1;
356 return Operand(ebp, -offset * kPointerSize);
357}
358
359
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000360void LCodeGen::WriteTranslation(LEnvironment* environment,
361 Translation* translation) {
362 if (environment == NULL) return;
363
364 // The translation includes one command per value in the environment.
365 int translation_size = environment->values()->length();
366 // The output frame height does not include the parameters.
367 int height = translation_size - environment->parameter_count();
368
369 WriteTranslation(environment->outer(), translation);
370 int closure_id = DefineDeoptimizationLiteral(environment->closure());
ulan@chromium.org967e2702012-02-28 09:49:15 +0000371 switch (environment->frame_type()) {
372 case JS_FUNCTION:
373 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
374 break;
375 case JS_CONSTRUCT:
376 translation->BeginConstructStubFrame(closure_id, translation_size);
377 break;
378 case ARGUMENTS_ADAPTOR:
379 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
380 break;
381 default:
382 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000383 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000384 for (int i = 0; i < translation_size; ++i) {
385 LOperand* value = environment->values()->at(i);
386 // spilled_registers_ and spilled_double_registers_ are either
387 // both NULL or both set.
388 if (environment->spilled_registers() != NULL && value != NULL) {
389 if (value->IsRegister() &&
390 environment->spilled_registers()[value->index()] != NULL) {
391 translation->MarkDuplicate();
392 AddToTranslation(translation,
393 environment->spilled_registers()[value->index()],
394 environment->HasTaggedValueAt(i));
395 } else if (
396 value->IsDoubleRegister() &&
397 environment->spilled_double_registers()[value->index()] != NULL) {
398 translation->MarkDuplicate();
399 AddToTranslation(
400 translation,
401 environment->spilled_double_registers()[value->index()],
402 false);
403 }
404 }
405
406 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
407 }
408}
409
410
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411void LCodeGen::AddToTranslation(Translation* translation,
412 LOperand* op,
413 bool is_tagged) {
414 if (op == NULL) {
415 // TODO(twuerthinger): Introduce marker operands to indicate that this value
416 // is not present and must be reconstructed from the deoptimizer. Currently
417 // this is only used for the arguments object.
418 translation->StoreArgumentsObject();
419 } else if (op->IsStackSlot()) {
420 if (is_tagged) {
421 translation->StoreStackSlot(op->index());
422 } else {
423 translation->StoreInt32StackSlot(op->index());
424 }
425 } else if (op->IsDoubleStackSlot()) {
426 translation->StoreDoubleStackSlot(op->index());
427 } else if (op->IsArgument()) {
428 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000429 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000430 translation->StoreStackSlot(src_index);
431 } else if (op->IsRegister()) {
432 Register reg = ToRegister(op);
433 if (is_tagged) {
434 translation->StoreRegister(reg);
435 } else {
436 translation->StoreInt32Register(reg);
437 }
438 } else if (op->IsDoubleRegister()) {
439 XMMRegister reg = ToDoubleRegister(op);
440 translation->StoreDoubleRegister(reg);
441 } else if (op->IsConstantOperand()) {
442 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
443 int src_index = DefineDeoptimizationLiteral(literal);
444 translation->StoreLiteral(src_index);
445 } else {
446 UNREACHABLE();
447 }
448}
449
450
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000451void LCodeGen::CallCodeGeneric(Handle<Code> code,
452 RelocInfo::Mode mode,
453 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000454 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000455 ASSERT(instr != NULL);
456 LPointerMap* pointers = instr->pointer_map();
457 RecordPosition(pointers->position());
458 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000459 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000460
461 // Signal that we don't inline smi code before these stubs in the
462 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000463 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000464 code->kind() == Code::COMPARE_IC) {
465 __ nop();
466 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467}
468
469
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000470void LCodeGen::CallCode(Handle<Code> code,
471 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000472 LInstruction* instr) {
473 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000474}
475
476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000478 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000479 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000480 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000481 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000482 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000483 RecordPosition(pointers->position());
484
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000485 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000486
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000487 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000488}
489
490
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000491void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
492 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000493 LInstruction* instr,
494 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000495 if (context->IsRegister()) {
496 if (!ToRegister(context).is(esi)) {
497 __ mov(esi, ToRegister(context));
498 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000499 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000500 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000501 } else if (context->IsConstantOperand()) {
502 Handle<Object> literal =
503 chunk_->LookupLiteral(LConstantOperand::cast(context));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000504 __ LoadHeapObject(esi, Handle<Context>::cast(literal));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000505 } else {
506 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000507 }
508
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000509 __ CallRuntimeSaveDoubles(id);
510 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000511 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000512}
513
514
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000515void LCodeGen::RegisterEnvironmentForDeoptimization(
516 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000517 if (!environment->HasBeenRegistered()) {
518 // Physical stack frame layout:
519 // -x ............. -4 0 ..................................... y
520 // [incoming arguments] [spill slots] [pushed outgoing arguments]
521
522 // Layout of the environment:
523 // 0 ..................................................... size-1
524 // [parameters] [locals] [expression stack including arguments]
525
526 // Layout of the translation:
527 // 0 ........................................................ size - 1 + 4
528 // [expression stack including arguments] [locals] [4 words] [parameters]
529 // |>------------ translation_size ------------<|
530
531 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000532 int jsframe_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
534 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000535 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000536 ++jsframe_count;
537 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000538 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000539 Translation translation(&translations_, frame_count, jsframe_count,
540 zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000541 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000542 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000543 int pc_offset = masm()->pc_offset();
544 environment->Register(deoptimization_index,
545 translation.index(),
546 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000547 deoptimizations_.Add(environment);
548 }
549}
550
551
552void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000553 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000554 ASSERT(environment->HasBeenRegistered());
555 int id = environment->deoptimization_index();
556 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000557 if (entry == NULL) {
558 Abort("bailout was not prepared");
559 return;
560 }
561
562 if (FLAG_deopt_every_n_times != 0) {
563 Handle<SharedFunctionInfo> shared(info_->shared_info());
564 Label no_deopt;
565 __ pushfd();
566 __ push(eax);
567 __ push(ebx);
568 __ mov(ebx, shared);
569 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
570 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000571 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000572 if (FLAG_trap_on_deopt) __ int3();
573 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
574 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
575 __ pop(ebx);
576 __ pop(eax);
577 __ popfd();
578 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
579
580 __ bind(&no_deopt);
581 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
582 __ pop(ebx);
583 __ pop(eax);
584 __ popfd();
585 }
586
587 if (cc == no_condition) {
588 if (FLAG_trap_on_deopt) __ int3();
589 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
590 } else {
591 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000592 Label done;
593 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000594 __ int3();
595 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
596 __ bind(&done);
597 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 }
600 }
601}
602
603
604void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
605 int length = deoptimizations_.length();
606 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000607 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000610 Handle<ByteArray> translations = translations_.CreateByteArray();
611 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
613
614 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000616 for (int i = 0; i < deoptimization_literals_.length(); i++) {
617 literals->set(i, *deoptimization_literals_[i]);
618 }
619 data->SetLiteralArray(*literals);
620
621 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
622 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
623
624 // Populate the deoptimization entries.
625 for (int i = 0; i < length; i++) {
626 LEnvironment* env = deoptimizations_[i];
627 data->SetAstId(i, Smi::FromInt(env->ast_id()));
628 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
629 data->SetArgumentsStackHeight(i,
630 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000631 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632 }
633 code->set_deoptimization_data(*data);
634}
635
636
637int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
638 int result = deoptimization_literals_.length();
639 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
640 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
641 }
642 deoptimization_literals_.Add(literal);
643 return result;
644}
645
646
647void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
648 ASSERT(deoptimization_literals_.length() == 0);
649
650 const ZoneList<Handle<JSFunction> >* inlined_closures =
651 chunk()->inlined_closures();
652
653 for (int i = 0, length = inlined_closures->length();
654 i < length;
655 i++) {
656 DefineDeoptimizationLiteral(inlined_closures->at(i));
657 }
658
659 inlined_function_count_ = deoptimization_literals_.length();
660}
661
662
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000663void LCodeGen::RecordSafepointWithLazyDeopt(
664 LInstruction* instr, SafepointMode safepoint_mode) {
665 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
666 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
667 } else {
668 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
669 RecordSafepointWithRegisters(
670 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
671 }
672}
673
674
ager@chromium.org378b34e2011-01-28 08:04:38 +0000675void LCodeGen::RecordSafepoint(
676 LPointerMap* pointers,
677 Safepoint::Kind kind,
678 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000679 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000680 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000681 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000682 Safepoint safepoint =
683 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 for (int i = 0; i < operands->length(); i++) {
685 LOperand* pointer = operands->at(i);
686 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000687 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000688 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
689 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000690 }
691 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000692}
693
694
695void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000696 Safepoint::DeoptMode mode) {
697 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000698}
699
700
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000701void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000702 LPointerMap empty_pointers(RelocInfo::kNoPosition);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000703 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000704}
705
706
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000707void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
708 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000709 Safepoint::DeoptMode mode) {
710 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000711}
712
713
714void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000715 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000716 masm()->positions_recorder()->RecordPosition(position);
717}
718
719
720void LCodeGen::DoLabel(LLabel* label) {
721 if (label->is_loop_header()) {
722 Comment(";;; B%d - LOOP entry", label->block_id());
723 } else {
724 Comment(";;; B%d", label->block_id());
725 }
726 __ bind(label->label());
727 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000728 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000729}
730
731
732void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000733 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000734}
735
736
737void LCodeGen::DoGap(LGap* gap) {
738 for (int i = LGap::FIRST_INNER_POSITION;
739 i <= LGap::LAST_INNER_POSITION;
740 i++) {
741 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
742 LParallelMove* move = gap->GetParallelMove(inner_pos);
743 if (move != NULL) DoParallelMove(move);
744 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745}
746
747
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000748void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
749 DoGap(instr);
750}
751
752
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000753void LCodeGen::DoParameter(LParameter* instr) {
754 // Nothing to do.
755}
756
757
758void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000759 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000760 ASSERT(ToRegister(instr->result()).is(eax));
761 switch (instr->hydrogen()->major_key()) {
762 case CodeStub::RegExpConstructResult: {
763 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000764 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000765 break;
766 }
767 case CodeStub::RegExpExec: {
768 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000769 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000770 break;
771 }
772 case CodeStub::SubString: {
773 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000774 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000775 break;
776 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000777 case CodeStub::NumberToString: {
778 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000779 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000780 break;
781 }
782 case CodeStub::StringAdd: {
783 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000784 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000785 break;
786 }
787 case CodeStub::StringCompare: {
788 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000789 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000790 break;
791 }
792 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000793 TranscendentalCacheStub stub(instr->transcendental_type(),
794 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000795 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000796 break;
797 }
798 default:
799 UNREACHABLE();
800 }
801}
802
803
804void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
805 // Nothing to do.
806}
807
808
809void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000810 if (instr->hydrogen()->HasPowerOf2Divisor()) {
811 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000812
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000813 int32_t divisor =
814 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000815
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000816 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000818 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000819 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000820 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000821 __ neg(dividend);
822 __ and_(dividend, divisor - 1);
823 __ neg(dividend);
824 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000825 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000826 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000827 } else {
828 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000829 }
830 __ bind(&positive_dividend);
831 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000832 __ bind(&done);
833 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000834 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000835 Register left_reg = ToRegister(instr->InputAt(0));
836 Register right_reg = ToRegister(instr->InputAt(1));
837 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000838
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000839 ASSERT(left_reg.is(eax));
840 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000841 ASSERT(!right_reg.is(eax));
842 ASSERT(!right_reg.is(edx));
843
844 // Check for x % 0.
845 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000846 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000847 DeoptimizeIf(zero, instr->environment());
848 }
849
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000850 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000851 __ j(zero, &remainder_eq_dividend, Label::kNear);
852 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000853
854 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000855 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000856 // The sign of the divisor doesn't matter.
857 __ neg(right_reg);
858
859 __ bind(&both_positive);
860 // If the dividend is smaller than the nonnegative
861 // divisor, the dividend is the result.
862 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000863 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000864
865 // Check if the divisor is a PowerOfTwo integer.
866 Register scratch = ToRegister(instr->TempAt(0));
867 __ mov(scratch, right_reg);
868 __ sub(Operand(scratch), Immediate(1));
869 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000870 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000871 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000872 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000873
874 __ bind(&do_subtraction);
875 const int kUnfolds = 3;
876 // Try a few subtractions of the dividend.
877 __ mov(scratch, left_reg);
878 for (int i = 0; i < kUnfolds; i++) {
879 // Reduce the dividend by the divisor.
880 __ sub(left_reg, Operand(right_reg));
881 // Check if the dividend is less than the divisor.
882 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000883 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000884 }
885 __ mov(left_reg, scratch);
886
887 // Slow case, using idiv instruction.
888 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000889 // Sign extend to edx.
890 __ cdq();
891
892 // Check for (0 % -x) that will produce negative zero.
893 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000894 Label positive_left;
895 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000896 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000897 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000898 __ idiv(right_reg);
899
900 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000901 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000902 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000903
904 DeoptimizeIf(no_condition, instr->environment());
905 __ bind(&positive_left);
906 __ idiv(right_reg);
907 __ bind(&done);
908 } else {
909 __ idiv(right_reg);
910 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000911 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000912
913 __ bind(&remainder_eq_dividend);
914 __ mov(result_reg, left_reg);
915
916 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000917 }
918}
919
920
921void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000922 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000923 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000924 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
925 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
926 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000927
928 Register left_reg = eax;
929
930 // Check for x / 0.
931 Register right_reg = ToRegister(right);
932 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
933 __ test(right_reg, ToOperand(right));
934 DeoptimizeIf(zero, instr->environment());
935 }
936
937 // Check for (0 / -x) that will produce negative zero.
938 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000939 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000940 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000941 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000942 __ test(right_reg, ToOperand(right));
943 DeoptimizeIf(sign, instr->environment());
944 __ bind(&left_not_zero);
945 }
946
947 // Check for (-kMinInt / -1).
948 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000949 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000951 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000952 __ cmp(right_reg, -1);
953 DeoptimizeIf(zero, instr->environment());
954 __ bind(&left_not_min_int);
955 }
956
957 // Sign extend to edx.
958 __ cdq();
959 __ idiv(right_reg);
960
961 // Deoptimize if remainder is not 0.
962 __ test(edx, Operand(edx));
963 DeoptimizeIf(not_zero, instr->environment());
964}
965
966
967void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000968 Register left = ToRegister(instr->InputAt(0));
969 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000970
971 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000972 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000973 }
974
975 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000976 // Try strength reductions on the multiplication.
977 // All replacement instructions are at most as long as the imul
978 // and have better latency.
979 int constant = ToInteger32(LConstantOperand::cast(right));
980 if (constant == -1) {
981 __ neg(left);
982 } else if (constant == 0) {
983 __ xor_(left, Operand(left));
984 } else if (constant == 2) {
985 __ add(left, Operand(left));
986 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
987 // If we know that the multiplication can't overflow, it's safe to
988 // use instructions that don't set the overflow flag for the
989 // multiplication.
990 switch (constant) {
991 case 1:
992 // Do nothing.
993 break;
994 case 3:
995 __ lea(left, Operand(left, left, times_2, 0));
996 break;
997 case 4:
998 __ shl(left, 2);
999 break;
1000 case 5:
1001 __ lea(left, Operand(left, left, times_4, 0));
1002 break;
1003 case 8:
1004 __ shl(left, 3);
1005 break;
1006 case 9:
1007 __ lea(left, Operand(left, left, times_8, 0));
1008 break;
1009 case 16:
1010 __ shl(left, 4);
1011 break;
1012 default:
1013 __ imul(left, left, constant);
1014 break;
1015 }
1016 } else {
1017 __ imul(left, left, constant);
1018 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 } else {
1020 __ imul(left, ToOperand(right));
1021 }
1022
1023 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1024 DeoptimizeIf(overflow, instr->environment());
1025 }
1026
1027 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1028 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001029 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001030 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001031 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001032 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001033 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001034 DeoptimizeIf(no_condition, instr->environment());
1035 }
1036 } else {
1037 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001038 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001039 DeoptimizeIf(sign, instr->environment());
1040 }
1041 __ bind(&done);
1042 }
1043}
1044
1045
1046void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001047 LOperand* left = instr->InputAt(0);
1048 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001049 ASSERT(left->Equals(instr->result()));
1050 ASSERT(left->IsRegister());
1051
1052 if (right->IsConstantOperand()) {
1053 int right_operand = ToInteger32(LConstantOperand::cast(right));
1054 switch (instr->op()) {
1055 case Token::BIT_AND:
1056 __ and_(ToRegister(left), right_operand);
1057 break;
1058 case Token::BIT_OR:
1059 __ or_(ToRegister(left), right_operand);
1060 break;
1061 case Token::BIT_XOR:
1062 __ xor_(ToRegister(left), right_operand);
1063 break;
1064 default:
1065 UNREACHABLE();
1066 break;
1067 }
1068 } else {
1069 switch (instr->op()) {
1070 case Token::BIT_AND:
1071 __ and_(ToRegister(left), ToOperand(right));
1072 break;
1073 case Token::BIT_OR:
1074 __ or_(ToRegister(left), ToOperand(right));
1075 break;
1076 case Token::BIT_XOR:
1077 __ xor_(ToRegister(left), ToOperand(right));
1078 break;
1079 default:
1080 UNREACHABLE();
1081 break;
1082 }
1083 }
1084}
1085
1086
1087void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001088 LOperand* left = instr->InputAt(0);
1089 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001090 ASSERT(left->Equals(instr->result()));
1091 ASSERT(left->IsRegister());
1092 if (right->IsRegister()) {
1093 ASSERT(ToRegister(right).is(ecx));
1094
1095 switch (instr->op()) {
1096 case Token::SAR:
1097 __ sar_cl(ToRegister(left));
1098 break;
1099 case Token::SHR:
1100 __ shr_cl(ToRegister(left));
1101 if (instr->can_deopt()) {
1102 __ test(ToRegister(left), Immediate(0x80000000));
1103 DeoptimizeIf(not_zero, instr->environment());
1104 }
1105 break;
1106 case Token::SHL:
1107 __ shl_cl(ToRegister(left));
1108 break;
1109 default:
1110 UNREACHABLE();
1111 break;
1112 }
1113 } else {
1114 int value = ToInteger32(LConstantOperand::cast(right));
1115 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1116 switch (instr->op()) {
1117 case Token::SAR:
1118 if (shift_count != 0) {
1119 __ sar(ToRegister(left), shift_count);
1120 }
1121 break;
1122 case Token::SHR:
1123 if (shift_count == 0 && instr->can_deopt()) {
1124 __ test(ToRegister(left), Immediate(0x80000000));
1125 DeoptimizeIf(not_zero, instr->environment());
1126 } else {
1127 __ shr(ToRegister(left), shift_count);
1128 }
1129 break;
1130 case Token::SHL:
1131 if (shift_count != 0) {
1132 __ shl(ToRegister(left), shift_count);
1133 }
1134 break;
1135 default:
1136 UNREACHABLE();
1137 break;
1138 }
1139 }
1140}
1141
1142
1143void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001144 LOperand* left = instr->InputAt(0);
1145 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001146 ASSERT(left->Equals(instr->result()));
1147
1148 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001149 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001150 } else {
1151 __ sub(ToRegister(left), ToOperand(right));
1152 }
1153 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1154 DeoptimizeIf(overflow, instr->environment());
1155 }
1156}
1157
1158
1159void LCodeGen::DoConstantI(LConstantI* instr) {
1160 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001161 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001162}
1163
1164
1165void LCodeGen::DoConstantD(LConstantD* instr) {
1166 ASSERT(instr->result()->IsDoubleRegister());
1167 XMMRegister res = ToDoubleRegister(instr->result());
1168 double v = instr->value();
1169 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1170 // do so if the constant is -0.0.
1171 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001172 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001173 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001174 Register temp = ToRegister(instr->TempAt(0));
1175 uint64_t int_val = BitCast<uint64_t, double>(v);
1176 int32_t lower = static_cast<int32_t>(int_val);
1177 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001178 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001179 CpuFeatures::Scope scope(SSE4_1);
1180 if (lower != 0) {
1181 __ Set(temp, Immediate(lower));
1182 __ movd(res, Operand(temp));
1183 __ Set(temp, Immediate(upper));
1184 __ pinsrd(res, Operand(temp), 1);
1185 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001186 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001187 __ Set(temp, Immediate(upper));
1188 __ pinsrd(res, Operand(temp), 1);
1189 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001190 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001191 __ Set(temp, Immediate(upper));
1192 __ movd(res, Operand(temp));
1193 __ psllq(res, 32);
1194 if (lower != 0) {
1195 __ Set(temp, Immediate(lower));
1196 __ movd(xmm0, Operand(temp));
1197 __ por(res, xmm0);
1198 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199 }
1200 }
1201}
1202
1203
1204void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001205 Register reg = ToRegister(instr->result());
1206 Handle<Object> handle = instr->value();
1207 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001208 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001209 } else {
1210 __ Set(reg, Immediate(handle));
1211 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001212}
1213
1214
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001215void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001216 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001217 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001218 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1219}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001220
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001221
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001222void LCodeGen::DoFixedArrayBaseLength(
1223 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001224 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001225 Register array = ToRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001226 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001227}
1228
1229
whesse@chromium.org7b260152011-06-20 15:33:18 +00001230void LCodeGen::DoElementsKind(LElementsKind* instr) {
1231 Register result = ToRegister(instr->result());
1232 Register input = ToRegister(instr->InputAt(0));
1233
1234 // Load map into |result|.
1235 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1236 // Load the map's "bit field 2" into |result|. We only need the first byte,
1237 // but the following masking takes care of that anyway.
1238 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1239 // Retrieve elements_kind from bit field 2.
1240 __ and_(result, Map::kElementsKindMask);
1241 __ shr(result, Map::kElementsKindShift);
1242}
1243
1244
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001245void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001246 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001247 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001248 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001249 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001250
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001251 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001252 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001253 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001254
1255 // If the object is not a value type, return the object.
1256 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001257 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001258 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1259
1260 __ bind(&done);
1261}
1262
1263
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001264void LCodeGen::DoDateField(LDateField* instr) {
1265 Register object = ToRegister(instr->InputAt(0));
1266 Register result = ToRegister(instr->result());
1267 Register scratch = ToRegister(instr->TempAt(0));
1268 Smi* index = instr->index();
1269 Label runtime, done;
1270 ASSERT(object.is(result));
1271 ASSERT(object.is(eax));
1272
1273#ifdef DEBUG
1274 __ AbortIfSmi(object);
1275 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
1276 __ Assert(equal, "Trying to get date field from non-date.");
1277#endif
1278
1279 if (index->value() == 0) {
1280 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1281 } else {
1282 if (index->value() < JSDate::kFirstUncachedField) {
1283 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1284 __ mov(scratch, Operand::StaticVariable(stamp));
1285 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1286 __ j(not_equal, &runtime, Label::kNear);
1287 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1288 kPointerSize * index->value()));
1289 __ jmp(&done);
1290 }
1291 __ bind(&runtime);
1292 __ PrepareCallCFunction(2, scratch);
1293 __ mov(Operand(esp, 0), object);
1294 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1295 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1296 __ bind(&done);
1297 }
1298}
1299
1300
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001301void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001302 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001303 ASSERT(input->Equals(instr->result()));
1304 __ not_(ToRegister(input));
1305}
1306
1307
1308void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001309 __ push(ToOperand(instr->value()));
1310 ASSERT(ToRegister(instr->context()).is(esi));
1311 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001312
1313 if (FLAG_debug_code) {
1314 Comment("Unreachable code.");
1315 __ int3();
1316 }
1317}
1318
1319
1320void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001321 LOperand* left = instr->InputAt(0);
1322 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001323 ASSERT(left->Equals(instr->result()));
1324
1325 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001326 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001327 } else {
1328 __ add(ToRegister(left), ToOperand(right));
1329 }
1330
1331 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1332 DeoptimizeIf(overflow, instr->environment());
1333 }
1334}
1335
1336
1337void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001338 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1339 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1340 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001341 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001342 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343 switch (instr->op()) {
1344 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001346 break;
1347 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001348 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001349 break;
1350 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001351 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352 break;
1353 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001354 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001355 break;
1356 case Token::MOD: {
1357 // Pass two doubles as arguments on the stack.
1358 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001359 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1360 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 __ CallCFunction(
1362 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1363 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001364
1365 // Return value is in st(0) on ia32.
1366 // Store it into the (fixed) result register.
1367 __ sub(Operand(esp), Immediate(kDoubleSize));
1368 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001369 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001370 __ add(Operand(esp), Immediate(kDoubleSize));
1371 break;
1372 }
1373 default:
1374 UNREACHABLE();
1375 break;
1376 }
1377}
1378
1379
1380void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001381 ASSERT(ToRegister(instr->context()).is(esi));
1382 ASSERT(ToRegister(instr->left()).is(edx));
1383 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001384 ASSERT(ToRegister(instr->result()).is(eax));
1385
danno@chromium.org40cb8782011-05-25 07:58:50 +00001386 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001387 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001388 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001389}
1390
1391
1392int LCodeGen::GetNextEmittedBlock(int block) {
1393 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1394 LLabel* label = chunk_->GetLabel(i);
1395 if (!label->HasReplacement()) return i;
1396 }
1397 return -1;
1398}
1399
1400
1401void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1402 int next_block = GetNextEmittedBlock(current_block_);
1403 right_block = chunk_->LookupDestination(right_block);
1404 left_block = chunk_->LookupDestination(left_block);
1405
1406 if (right_block == left_block) {
1407 EmitGoto(left_block);
1408 } else if (left_block == next_block) {
1409 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1410 } else if (right_block == next_block) {
1411 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1412 } else {
1413 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1414 __ jmp(chunk_->GetAssemblyLabel(right_block));
1415 }
1416}
1417
1418
1419void LCodeGen::DoBranch(LBranch* instr) {
1420 int true_block = chunk_->LookupDestination(instr->true_block_id());
1421 int false_block = chunk_->LookupDestination(instr->false_block_id());
1422
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001423 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001424 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001425 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426 __ test(reg, Operand(reg));
1427 EmitBranch(true_block, false_block, not_zero);
1428 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001429 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001430 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001431 __ ucomisd(reg, xmm0);
1432 EmitBranch(true_block, false_block, not_equal);
1433 } else {
1434 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001435 Register reg = ToRegister(instr->InputAt(0));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001436 HType type = instr->hydrogen()->value()->type();
1437 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001439 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001440 } else if (type.IsSmi()) {
1441 __ test(reg, Operand(reg));
1442 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001443 } else {
1444 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1445 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1446
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001447 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1448 // Avoid deopts in the case where we've never executed this path before.
1449 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001450
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001451 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1452 // undefined -> false.
1453 __ cmp(reg, factory()->undefined_value());
1454 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001455 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001456 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1457 // true -> true.
1458 __ cmp(reg, factory()->true_value());
1459 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001460 // false -> false.
1461 __ cmp(reg, factory()->false_value());
1462 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001463 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001464 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1465 // 'null' -> false.
1466 __ cmp(reg, factory()->null_value());
1467 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001468 }
1469
1470 if (expected.Contains(ToBooleanStub::SMI)) {
1471 // Smis: 0 -> false, all other -> true.
1472 __ test(reg, Operand(reg));
1473 __ j(equal, false_label);
1474 __ JumpIfSmi(reg, true_label);
1475 } else if (expected.NeedsMap()) {
1476 // If we need a map later and have a Smi -> deopt.
1477 __ test(reg, Immediate(kSmiTagMask));
1478 DeoptimizeIf(zero, instr->environment());
1479 }
1480
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001481 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001482 if (expected.NeedsMap()) {
1483 map = ToRegister(instr->TempAt(0));
1484 ASSERT(!map.is(reg));
1485 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001486
1487 if (expected.CanBeUndetectable()) {
1488 // Undetectable -> false.
1489 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1490 1 << Map::kIsUndetectable);
1491 __ j(not_zero, false_label);
1492 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001493 }
1494
1495 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1496 // spec object -> true.
1497 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1498 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001499 }
1500
1501 if (expected.Contains(ToBooleanStub::STRING)) {
1502 // String value -> false iff empty.
1503 Label not_string;
1504 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1505 __ j(above_equal, &not_string, Label::kNear);
1506 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1507 __ j(not_zero, true_label);
1508 __ jmp(false_label);
1509 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001510 }
1511
1512 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1513 // heap number -> false iff +0, -0, or NaN.
1514 Label not_heap_number;
1515 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1516 factory()->heap_number_map());
1517 __ j(not_equal, &not_heap_number, Label::kNear);
1518 __ fldz();
1519 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1520 __ FCmp();
1521 __ j(zero, false_label);
1522 __ jmp(true_label);
1523 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001524 }
1525
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001526 // We've seen something for the first time -> deopt.
1527 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001528 }
1529 }
1530}
1531
1532
ager@chromium.org04921a82011-06-27 13:21:41 +00001533void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001534 block = chunk_->LookupDestination(block);
1535 int next_block = GetNextEmittedBlock(current_block_);
1536 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001537 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001538 }
1539}
1540
1541
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001542void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001543 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001544}
1545
1546
1547Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1548 Condition cond = no_condition;
1549 switch (op) {
1550 case Token::EQ:
1551 case Token::EQ_STRICT:
1552 cond = equal;
1553 break;
1554 case Token::LT:
1555 cond = is_unsigned ? below : less;
1556 break;
1557 case Token::GT:
1558 cond = is_unsigned ? above : greater;
1559 break;
1560 case Token::LTE:
1561 cond = is_unsigned ? below_equal : less_equal;
1562 break;
1563 case Token::GTE:
1564 cond = is_unsigned ? above_equal : greater_equal;
1565 break;
1566 case Token::IN:
1567 case Token::INSTANCEOF:
1568 default:
1569 UNREACHABLE();
1570 }
1571 return cond;
1572}
1573
1574
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001575void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001576 LOperand* left = instr->InputAt(0);
1577 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001578 int false_block = chunk_->LookupDestination(instr->false_block_id());
1579 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001581
1582 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1583 // We can statically evaluate the comparison.
1584 double left_val = ToDouble(LConstantOperand::cast(left));
1585 double right_val = ToDouble(LConstantOperand::cast(right));
1586 int next_block =
1587 EvalComparison(instr->op(), left_val, right_val) ? true_block
1588 : false_block;
1589 EmitGoto(next_block);
1590 } else {
1591 if (instr->is_double()) {
1592 // Don't base result on EFLAGS when a NaN is involved. Instead
1593 // jump to the false block.
1594 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1595 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1596 } else {
1597 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001598 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001599 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001600 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001601 // We transposed the operands. Reverse the condition.
1602 cc = ReverseCondition(cc);
1603 } else {
1604 __ cmp(ToRegister(left), ToOperand(right));
1605 }
1606 }
1607 EmitBranch(true_block, false_block, cc);
1608 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609}
1610
1611
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001612void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001613 Register left = ToRegister(instr->InputAt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001614 Operand right = ToOperand(instr->InputAt(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001615 int false_block = chunk_->LookupDestination(instr->false_block_id());
1616 int true_block = chunk_->LookupDestination(instr->true_block_id());
1617
1618 __ cmp(left, Operand(right));
1619 EmitBranch(true_block, false_block, equal);
1620}
1621
1622
whesse@chromium.org7b260152011-06-20 15:33:18 +00001623void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
1624 Register left = ToRegister(instr->InputAt(0));
1625 int true_block = chunk_->LookupDestination(instr->true_block_id());
1626 int false_block = chunk_->LookupDestination(instr->false_block_id());
1627
1628 __ cmp(left, instr->hydrogen()->right());
1629 EmitBranch(true_block, false_block, equal);
1630}
1631
1632
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001633void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001634 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001635 int false_block = chunk_->LookupDestination(instr->false_block_id());
1636
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 // If the expression is known to be untagged or a smi, then it's definitely
1638 // not null, and it can't be a an undetectable object.
1639 if (instr->hydrogen()->representation().IsSpecialization() ||
1640 instr->hydrogen()->type().IsSmi()) {
1641 EmitGoto(false_block);
1642 return;
1643 }
1644
1645 int true_block = chunk_->LookupDestination(instr->true_block_id());
1646 Handle<Object> nil_value = instr->nil() == kNullValue ?
1647 factory()->null_value() :
1648 factory()->undefined_value();
1649 __ cmp(reg, nil_value);
1650 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001651 EmitBranch(true_block, false_block, equal);
1652 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001653 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
1654 factory()->undefined_value() :
1655 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001656 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1657 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1658 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001659 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001660 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001661 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001662 // Check for undetectable objects by looking in the bit field in
1663 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001664 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001665 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1666 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1667 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1668 EmitBranch(true_block, false_block, not_zero);
1669 }
1670}
1671
1672
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001673Condition LCodeGen::EmitIsObject(Register input,
1674 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001675 Label* is_not_object,
1676 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001677 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001678
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001680 __ j(equal, is_object);
1681
1682 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1683 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001684 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
1685 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686 __ j(not_zero, is_not_object);
1687
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001688 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
1689 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001690 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001691 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001692 return below_equal;
1693}
1694
1695
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001696void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001697 Register reg = ToRegister(instr->InputAt(0));
1698 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001699
1700 int true_block = chunk_->LookupDestination(instr->true_block_id());
1701 int false_block = chunk_->LookupDestination(instr->false_block_id());
1702 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1703 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1704
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001705 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001706
1707 EmitBranch(true_block, false_block, true_cond);
1708}
1709
1710
erikcorry0ad885c2011-11-21 13:51:57 +00001711Condition LCodeGen::EmitIsString(Register input,
1712 Register temp1,
1713 Label* is_not_string) {
1714 __ JumpIfSmi(input, is_not_string);
1715
1716 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
1717
1718 return cond;
1719}
1720
1721
1722void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
1723 Register reg = ToRegister(instr->InputAt(0));
1724 Register temp = ToRegister(instr->TempAt(0));
1725
1726 int true_block = chunk_->LookupDestination(instr->true_block_id());
1727 int false_block = chunk_->LookupDestination(instr->false_block_id());
1728 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1729
1730 Condition true_cond = EmitIsString(reg, temp, false_label);
1731
1732 EmitBranch(true_block, false_block, true_cond);
1733}
1734
1735
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001736void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001737 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001738
1739 int true_block = chunk_->LookupDestination(instr->true_block_id());
1740 int false_block = chunk_->LookupDestination(instr->false_block_id());
1741
1742 __ test(input, Immediate(kSmiTagMask));
1743 EmitBranch(true_block, false_block, zero);
1744}
1745
1746
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001747void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1748 Register input = ToRegister(instr->InputAt(0));
1749 Register temp = ToRegister(instr->TempAt(0));
1750
1751 int true_block = chunk_->LookupDestination(instr->true_block_id());
1752 int false_block = chunk_->LookupDestination(instr->false_block_id());
1753
1754 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001755 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001756 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1757 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1758 1 << Map::kIsUndetectable);
1759 EmitBranch(true_block, false_block, not_zero);
1760}
1761
1762
erikcorry0ad885c2011-11-21 13:51:57 +00001763static Condition ComputeCompareCondition(Token::Value op) {
1764 switch (op) {
1765 case Token::EQ_STRICT:
1766 case Token::EQ:
1767 return equal;
1768 case Token::LT:
1769 return less;
1770 case Token::GT:
1771 return greater;
1772 case Token::LTE:
1773 return less_equal;
1774 case Token::GTE:
1775 return greater_equal;
1776 default:
1777 UNREACHABLE();
1778 return no_condition;
1779 }
1780}
1781
1782
1783void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
1784 Token::Value op = instr->op();
1785 int true_block = chunk_->LookupDestination(instr->true_block_id());
1786 int false_block = chunk_->LookupDestination(instr->false_block_id());
1787
1788 Handle<Code> ic = CompareIC::GetUninitialized(op);
1789 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1790
1791 Condition condition = ComputeCompareCondition(op);
1792 __ test(eax, Operand(eax));
1793
1794 EmitBranch(true_block, false_block, condition);
1795}
1796
1797
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001798static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001799 InstanceType from = instr->from();
1800 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001801 if (from == FIRST_TYPE) return to;
1802 ASSERT(from == to || to == LAST_TYPE);
1803 return from;
1804}
1805
1806
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001807static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001808 InstanceType from = instr->from();
1809 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001810 if (from == to) return equal;
1811 if (to == LAST_TYPE) return above_equal;
1812 if (from == FIRST_TYPE) return below_equal;
1813 UNREACHABLE();
1814 return equal;
1815}
1816
1817
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001818void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001819 Register input = ToRegister(instr->InputAt(0));
1820 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001821
1822 int true_block = chunk_->LookupDestination(instr->true_block_id());
1823 int false_block = chunk_->LookupDestination(instr->false_block_id());
1824
1825 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1826
whesse@chromium.org7b260152011-06-20 15:33:18 +00001827 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001828
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001829 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1830 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001831}
1832
1833
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001834void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1835 Register input = ToRegister(instr->InputAt(0));
1836 Register result = ToRegister(instr->result());
1837
1838 if (FLAG_debug_code) {
1839 __ AbortIfNotString(input);
1840 }
1841
1842 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
1843 __ IndexFromHash(result, result);
1844}
1845
1846
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001847void LCodeGen::DoHasCachedArrayIndexAndBranch(
1848 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001849 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001850
1851 int true_block = chunk_->LookupDestination(instr->true_block_id());
1852 int false_block = chunk_->LookupDestination(instr->false_block_id());
1853
1854 __ test(FieldOperand(input, String::kHashFieldOffset),
1855 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001856 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001857}
1858
1859
1860// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001861// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001862void LCodeGen::EmitClassOfTest(Label* is_true,
1863 Label* is_false,
1864 Handle<String>class_name,
1865 Register input,
1866 Register temp,
1867 Register temp2) {
1868 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001869 ASSERT(!input.is(temp2));
1870 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001871 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001872
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001873 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001874 // Assuming the following assertions, we can use the same compares to test
1875 // for both being a function type and being in the object type range.
1876 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
1877 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1878 FIRST_SPEC_OBJECT_TYPE + 1);
1879 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1880 LAST_SPEC_OBJECT_TYPE - 1);
1881 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1882 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
1883 __ j(below, is_false);
1884 __ j(equal, is_true);
1885 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
1886 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001887 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001888 // Faster code path to avoid two compares: subtract lower bound from the
1889 // actual type and do a signed compare with the width of the type range.
1890 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00001891 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001892 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00001893 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
1894 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001895 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 }
1897
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001898 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001899 // Check if the constructor in the map is a function.
1900 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 // Objects with a non-function constructor have class 'Object'.
1902 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1903 if (class_name->IsEqualTo(CStrVector("Object"))) {
1904 __ j(not_equal, is_true);
1905 } else {
1906 __ j(not_equal, is_false);
1907 }
1908
1909 // temp now contains the constructor function. Grab the
1910 // instance class name from there.
1911 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1912 __ mov(temp, FieldOperand(temp,
1913 SharedFunctionInfo::kInstanceClassNameOffset));
1914 // The class name we are testing against is a symbol because it's a literal.
1915 // The name in the constructor is a symbol because of the way the context is
1916 // booted. This routine isn't expected to work for random API-created
1917 // classes and it doesn't have to because you can't access it with natives
1918 // syntax. Since both sides are symbols it is sufficient to use an identity
1919 // comparison.
1920 __ cmp(temp, class_name);
1921 // End with the answer in the z flag.
1922}
1923
1924
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001925void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001926 Register input = ToRegister(instr->InputAt(0));
1927 Register temp = ToRegister(instr->TempAt(0));
1928 Register temp2 = ToRegister(instr->TempAt(1));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001929
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001930 Handle<String> class_name = instr->hydrogen()->class_name();
1931
1932 int true_block = chunk_->LookupDestination(instr->true_block_id());
1933 int false_block = chunk_->LookupDestination(instr->false_block_id());
1934
1935 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1936 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1937
1938 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1939
1940 EmitBranch(true_block, false_block, equal);
1941}
1942
1943
1944void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001945 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946 int true_block = instr->true_block_id();
1947 int false_block = instr->false_block_id();
1948
1949 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1950 EmitBranch(true_block, false_block, equal);
1951}
1952
1953
1954void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001955 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001956 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001957 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001958 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001959
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001960 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001961 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001962 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001963 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001964 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001965 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001967 __ bind(&done);
1968}
1969
1970
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001971void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1972 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1973 public:
1974 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1975 LInstanceOfKnownGlobal* instr)
1976 : LDeferredCode(codegen), instr_(instr) { }
1977 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001978 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001979 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001980 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001981 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001982 private:
1983 LInstanceOfKnownGlobal* instr_;
1984 Label map_check_;
1985 };
1986
1987 DeferredInstanceOfKnownGlobal* deferred;
1988 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1989
1990 Label done, false_result;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001991 Register object = ToRegister(instr->InputAt(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001992 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001993
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001994 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001995 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001996
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001997 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001998 // hole value will be patched to the last map/result pair generated by the
1999 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002000 Label cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002001 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002002 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2003 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002004 Handle<JSGlobalPropertyCell> cache_cell =
2005 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2006 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002007 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002009 __ jmp(&done);
2010
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002011 // The inlined call site cache did not match. Check for null and string
2012 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002013 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002014 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002016 __ j(equal, &false_result);
2017
2018 // String values are not instances of anything.
2019 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2020 __ j(is_string, &false_result);
2021
2022 // Go to the deferred code.
2023 __ jmp(deferred->entry());
2024
2025 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002027
2028 // Here result has either true or false. Deferred code also produces true or
2029 // false object.
2030 __ bind(deferred->exit());
2031 __ bind(&done);
2032}
2033
2034
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002035void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2036 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002037 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002038
2039 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2040 flags = static_cast<InstanceofStub::Flags>(
2041 flags | InstanceofStub::kArgsInRegisters);
2042 flags = static_cast<InstanceofStub::Flags>(
2043 flags | InstanceofStub::kCallSiteInlineCheck);
2044 flags = static_cast<InstanceofStub::Flags>(
2045 flags | InstanceofStub::kReturnTrueFalseObject);
2046 InstanceofStub stub(flags);
2047
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002048 // Get the temp register reserved by the instruction. This needs to be a
2049 // register which is pushed last by PushSafepointRegisters as top of the
2050 // stack is used to pass the offset to the location of the map check to
2051 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002052 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002053 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002054 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002055 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002056 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002057 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002058 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002059 CallCodeGeneric(stub.GetCode(),
2060 RelocInfo::CODE_TARGET,
2061 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002062 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002063 // Get the deoptimization index of the LLazyBailout-environment that
2064 // corresponds to this instruction.
2065 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002066 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2067
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002068 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002069 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002070}
2071
2072
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002073void LCodeGen::DoCmpT(LCmpT* instr) {
2074 Token::Value op = instr->op();
2075
2076 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002077 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002078
2079 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002080 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002081 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002082 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002083 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002084 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002085 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002086 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002087 __ bind(&done);
2088}
2089
2090
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002091void LCodeGen::DoReturn(LReturn* instr) {
2092 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002093 // Preserve the return value on the stack and rely on the runtime call
2094 // to return the value in the same register. We're leaving the code
2095 // managed by the register allocator and tearing down the frame, it's
2096 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002097 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002098 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002099 __ CallRuntime(Runtime::kTraceExit, 1);
2100 }
2101 __ mov(esp, ebp);
2102 __ pop(ebp);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002103 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002104}
2105
2106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002107void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002108 Register result = ToRegister(instr->result());
2109 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002110 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002111 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002112 DeoptimizeIf(equal, instr->environment());
2113 }
2114}
2115
2116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002117void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2118 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002119 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002120 ASSERT(ToRegister(instr->result()).is(eax));
2121
2122 __ mov(ecx, instr->name());
2123 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2124 RelocInfo::CODE_TARGET_CONTEXT;
2125 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002126 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002127}
2128
2129
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002130void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002131 Register value = ToRegister(instr->value());
2132 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002133
2134 // If the cell we are storing to contains the hole it could have
2135 // been deleted from the property dictionary. In that case, we need
2136 // to update the property details in the property dictionary to mark
2137 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002138 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002139 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002140 DeoptimizeIf(equal, instr->environment());
2141 }
2142
2143 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002144 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002145 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002146}
2147
2148
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002149void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2150 ASSERT(ToRegister(instr->context()).is(esi));
2151 ASSERT(ToRegister(instr->global_object()).is(edx));
2152 ASSERT(ToRegister(instr->value()).is(eax));
2153
2154 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002155 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002156 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2157 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002158 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002159}
2160
2161
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002162void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002163 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002164 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002165 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002166
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002167 if (instr->hydrogen()->RequiresHoleCheck()) {
2168 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002169 if (instr->hydrogen()->DeoptimizesOnHole()) {
2170 DeoptimizeIf(equal, instr->environment());
2171 } else {
2172 Label is_not_hole;
2173 __ j(not_equal, &is_not_hole, Label::kNear);
2174 __ mov(result, factory()->undefined_value());
2175 __ bind(&is_not_hole);
2176 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002177 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002178}
2179
2180
2181void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2182 Register context = ToRegister(instr->context());
2183 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002184
2185 Label skip_assignment;
2186
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002187 Operand target = ContextOperand(context, instr->slot_index());
2188 if (instr->hydrogen()->RequiresHoleCheck()) {
2189 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002190 if (instr->hydrogen()->DeoptimizesOnHole()) {
2191 DeoptimizeIf(equal, instr->environment());
2192 } else {
2193 __ j(not_equal, &skip_assignment, Label::kNear);
2194 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002195 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002196
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002197 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002198 if (instr->hydrogen()->NeedsWriteBarrier()) {
2199 HType type = instr->hydrogen()->value()->type();
2200 SmiCheck check_needed =
2201 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002202 Register temp = ToRegister(instr->TempAt(0));
2203 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002204 __ RecordWriteContextSlot(context,
2205 offset,
2206 value,
2207 temp,
2208 kSaveFPRegs,
2209 EMIT_REMEMBERED_SET,
2210 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002211 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002212
2213 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002214}
2215
2216
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002217void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002218 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002219 Register result = ToRegister(instr->result());
2220 if (instr->hydrogen()->is_in_object()) {
2221 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2222 } else {
2223 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2224 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2225 }
2226}
2227
2228
lrn@chromium.org1c092762011-05-09 09:42:16 +00002229void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2230 Register object,
2231 Handle<Map> type,
2232 Handle<String> name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002233 LookupResult lookup(isolate());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002234 type->LookupInDescriptors(NULL, *name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002235 ASSERT(lookup.IsFound() &&
lrn@chromium.org1c092762011-05-09 09:42:16 +00002236 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2237 if (lookup.type() == FIELD) {
2238 int index = lookup.GetLocalFieldIndexFromMap(*type);
2239 int offset = index * kPointerSize;
2240 if (index < 0) {
2241 // Negative property indices are in-object properties, indexed
2242 // from the end of the fixed part of the object.
2243 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2244 } else {
2245 // Non-negative property indices are in the properties array.
2246 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2247 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2248 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002249 } else {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002250 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002251 __ LoadHeapObject(result, function);
2252 }
2253}
2254
2255
2256void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2257 ASSERT(!operand->IsDoubleRegister());
2258 if (operand->IsConstantOperand()) {
2259 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2260 if (object->IsSmi()) {
2261 __ Push(Handle<Smi>::cast(object));
2262 } else {
2263 __ PushHeapObject(Handle<HeapObject>::cast(object));
2264 }
2265 } else if (operand->IsRegister()) {
2266 __ push(ToRegister(operand));
2267 } else {
2268 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002269 }
2270}
2271
2272
2273void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2274 Register object = ToRegister(instr->object());
2275 Register result = ToRegister(instr->result());
2276
2277 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002278 bool need_generic = instr->hydrogen()->need_generic();
2279
2280 if (map_count == 0 && !need_generic) {
2281 DeoptimizeIf(no_condition, instr->environment());
2282 return;
2283 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002284 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002285 Label done;
2286 for (int i = 0; i < map_count; ++i) {
2287 bool last = (i == map_count - 1);
2288 Handle<Map> map = instr->hydrogen()->types()->at(i);
2289 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2290 if (last && !need_generic) {
2291 DeoptimizeIf(not_equal, instr->environment());
2292 EmitLoadFieldOrConstantFunction(result, object, map, name);
2293 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002294 Label next;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002295 __ j(not_equal, &next, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002296 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002297 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002298 __ bind(&next);
2299 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002300 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002301 if (need_generic) {
2302 __ mov(ecx, name);
2303 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2304 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2305 }
2306 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002307}
2308
2309
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002310void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002311 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002312 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002313 ASSERT(ToRegister(instr->result()).is(eax));
2314
2315 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002316 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002317 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002318}
2319
2320
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002321void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2322 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002323 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002324 Register result = ToRegister(instr->result());
2325
2326 // Check that the function really is a function.
2327 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2328 DeoptimizeIf(not_equal, instr->environment());
2329
2330 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002331 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002332 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2333 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002334 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002335
2336 // Get the prototype or initial map from the function.
2337 __ mov(result,
2338 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2339
2340 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002341 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002342 DeoptimizeIf(equal, instr->environment());
2343
2344 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002345 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002346 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002347 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002348
2349 // Get the prototype from the initial map.
2350 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002351 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002352
2353 // Non-instance prototype: Fetch prototype from constructor field
2354 // in the function's map.
2355 __ bind(&non_instance);
2356 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2357
2358 // All done.
2359 __ bind(&done);
2360}
2361
2362
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002363void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002364 Register result = ToRegister(instr->result());
2365 Register input = ToRegister(instr->InputAt(0));
2366 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002367 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002368 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002369 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002370 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002371 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002372 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002373 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002374 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002375 Register temp((result.is(eax)) ? ebx : eax);
2376 __ push(temp);
2377 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002378 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2379 __ and_(temp, Map::kElementsKindMask);
2380 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002381 __ cmp(temp, GetInitialFastElementsKind());
2382 __ j(less, &fail, Label::kNear);
2383 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
2384 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002385 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002386 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002387 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002388 __ j(less_equal, &ok, Label::kNear);
2389 __ bind(&fail);
2390 __ Abort("Check for fast or external elements failed.");
2391 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002392 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002393 __ bind(&done);
2394 }
2395}
2396
2397
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002398void LCodeGen::DoLoadExternalArrayPointer(
2399 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002400 Register result = ToRegister(instr->result());
2401 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002402 __ mov(result, FieldOperand(input,
2403 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002404}
2405
2406
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002407void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2408 Register arguments = ToRegister(instr->arguments());
2409 Register length = ToRegister(instr->length());
2410 Operand index = ToOperand(instr->index());
2411 Register result = ToRegister(instr->result());
2412
2413 __ sub(length, index);
2414 DeoptimizeIf(below_equal, instr->environment());
2415
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002416 // There are two words between the frame pointer and the last argument.
2417 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002418 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2419}
2420
2421
2422void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002423 Register result = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002424
2425 // Load the result.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002426 __ mov(result,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002427 BuildFastArrayOperand(instr->elements(),
2428 instr->key(),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002429 FAST_ELEMENTS,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002430 FixedArray::kHeaderSize - kHeapObjectTag,
2431 instr->additional_index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002432
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002433 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002434 if (instr->hydrogen()->RequiresHoleCheck()) {
2435 __ cmp(result, factory()->the_hole_value());
2436 DeoptimizeIf(equal, instr->environment());
2437 }
2438}
2439
2440
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002441void LCodeGen::DoLoadKeyedFastDoubleElement(
2442 LLoadKeyedFastDoubleElement* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002443 XMMRegister result = ToDoubleRegister(instr->result());
2444
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002445 if (instr->hydrogen()->RequiresHoleCheck()) {
2446 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2447 sizeof(kHoleNanLower32);
2448 Operand hole_check_operand = BuildFastArrayOperand(
2449 instr->elements(), instr->key(),
2450 FAST_DOUBLE_ELEMENTS,
2451 offset,
2452 instr->additional_index());
2453 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
2454 DeoptimizeIf(equal, instr->environment());
2455 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002456
2457 Operand double_load_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002458 instr->elements(),
2459 instr->key(),
2460 FAST_DOUBLE_ELEMENTS,
2461 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
2462 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002463 __ movdbl(result, double_load_operand);
2464}
2465
2466
2467Operand LCodeGen::BuildFastArrayOperand(
danno@chromium.orgb6451162011-08-17 14:33:23 +00002468 LOperand* elements_pointer,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002469 LOperand* key,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002470 ElementsKind elements_kind,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002471 uint32_t offset,
2472 uint32_t additional_index) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00002473 Register elements_pointer_reg = ToRegister(elements_pointer);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002474 int shift_size = ElementsKindToShiftSize(elements_kind);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002475 if (key->IsConstantOperand()) {
2476 int constant_value = ToInteger32(LConstantOperand::cast(key));
2477 if (constant_value & 0xF0000000) {
2478 Abort("array index constant value too big");
2479 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002480 return Operand(elements_pointer_reg,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002481 ((constant_value + additional_index) << shift_size)
2482 + offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002483 } else {
2484 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002485 return Operand(elements_pointer_reg,
2486 ToRegister(key),
2487 scale_factor,
2488 offset + (additional_index << shift_size));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002489 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002490}
2491
2492
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002493void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2494 LLoadKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002495 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002496 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002497 instr->key(),
2498 elements_kind,
2499 0,
2500 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002501 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002502 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002503 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002504 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002505 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002506 __ movdbl(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002507 } else {
2508 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002509 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002510 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002511 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002512 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002513 case EXTERNAL_PIXEL_ELEMENTS:
2514 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002515 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002516 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002517 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002518 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002519 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002520 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002521 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002522 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002523 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002524 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002525 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002526 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002527 __ mov(result, operand);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002528 __ test(result, Operand(result));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002529 // TODO(danno): we could be more clever here, perhaps having a special
2530 // version of the stub that detects if the overflow case actually
2531 // happens, and generate code that returns a double rather than int.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002532 DeoptimizeIf(negative, instr->environment());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002533 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002534 case EXTERNAL_FLOAT_ELEMENTS:
2535 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002536 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002537 case FAST_ELEMENTS:
2538 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002539 case FAST_HOLEY_SMI_ELEMENTS:
2540 case FAST_HOLEY_ELEMENTS:
2541 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002542 case DICTIONARY_ELEMENTS:
2543 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002544 UNREACHABLE();
2545 break;
2546 }
2547 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002548}
2549
2550
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002551void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002552 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002553 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002554 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002555
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002556 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002557 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002558}
2559
2560
2561void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2562 Register result = ToRegister(instr->result());
2563
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002564 if (instr->hydrogen()->from_inlined()) {
2565 __ lea(result, Operand(esp, -2 * kPointerSize));
2566 } else {
2567 // Check for arguments adapter frame.
2568 Label done, adapted;
2569 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2570 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2571 __ cmp(Operand(result),
2572 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2573 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002574
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002575 // No arguments adaptor frame.
2576 __ mov(result, Operand(ebp));
2577 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002578
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002579 // Arguments adaptor frame present.
2580 __ bind(&adapted);
2581 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002582
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002583 // Result is the frame pointer for the frame if not adapted and for the real
2584 // frame below the adaptor frame if adapted.
2585 __ bind(&done);
2586 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002587}
2588
2589
2590void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002591 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002592 Register result = ToRegister(instr->result());
2593
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002594 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002595
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002596 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002597 __ cmp(ebp, elem);
2598 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002599 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002600
2601 // Arguments adaptor frame present. Get argument length from there.
2602 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2603 __ mov(result, Operand(result,
2604 ArgumentsAdaptorFrameConstants::kLengthOffset));
2605 __ SmiUntag(result);
2606
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002607 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002608 __ bind(&done);
2609}
2610
2611
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002612void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002613 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002614 Register function = ToRegister(instr->function());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002615 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002616
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002617 // If the receiver is null or undefined, we have to pass the global
2618 // object as a receiver to normal functions. Values have to be
2619 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002620 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002621
2622 // Do not transform the receiver to object for strict mode
2623 // functions.
2624 __ mov(scratch,
2625 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2626 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
2627 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
2628 __ j(not_equal, &receiver_ok, Label::kNear);
2629
2630 // Do not transform the receiver to object for builtins.
2631 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
2632 1 << SharedFunctionInfo::kNativeBitWithinByte);
2633 __ j(not_equal, &receiver_ok, Label::kNear);
2634
2635 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002636 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002637 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002638 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002639 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002640
2641 // The receiver should be a JS object.
2642 __ test(receiver, Immediate(kSmiTagMask));
2643 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002644 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002645 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002646 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002647
2648 __ bind(&global_object);
2649 // TODO(kmillikin): We have a hydrogen value for the global object. See
2650 // if it's better to use it than to explicitly fetch it from the context
2651 // here.
2652 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2653 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002654 __ mov(receiver,
2655 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002656 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002657}
2658
2659
2660void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2661 Register receiver = ToRegister(instr->receiver());
2662 Register function = ToRegister(instr->function());
2663 Register length = ToRegister(instr->length());
2664 Register elements = ToRegister(instr->elements());
2665 ASSERT(receiver.is(eax)); // Used for parameter count.
2666 ASSERT(function.is(edi)); // Required by InvokeFunction.
2667 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002668
2669 // Copy the arguments to this function possibly from the
2670 // adaptor frame below it.
2671 const uint32_t kArgumentsLimit = 1 * KB;
2672 __ cmp(length, kArgumentsLimit);
2673 DeoptimizeIf(above, instr->environment());
2674
2675 __ push(receiver);
2676 __ mov(receiver, length);
2677
2678 // Loop through the arguments pushing them onto the execution
2679 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002680 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002681 // length is a small non-negative integer, due to the test above.
2682 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002683 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002684 __ bind(&loop);
2685 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2686 __ dec(length);
2687 __ j(not_zero, &loop);
2688
2689 // Invoke the function.
2690 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002691 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002692 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002693 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002694 SafepointGenerator safepoint_generator(
2695 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002696 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002697 __ InvokeFunction(function, actual, CALL_FUNCTION,
2698 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002699}
2700
2701
2702void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002703 LOperand* argument = instr->InputAt(0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002704 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002705}
2706
2707
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002708void LCodeGen::DoDrop(LDrop* instr) {
2709 __ Drop(instr->count());
2710}
2711
2712
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002713void LCodeGen::DoThisFunction(LThisFunction* instr) {
2714 Register result = ToRegister(instr->result());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002715 __ LoadHeapObject(result, instr->hydrogen()->closure());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002716}
2717
2718
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002719void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002720 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002721 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002722}
2723
2724
2725void LCodeGen::DoOuterContext(LOuterContext* instr) {
2726 Register context = ToRegister(instr->context());
2727 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002728 __ mov(result,
2729 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002730}
2731
2732
yangguo@chromium.org56454712012-02-16 15:33:53 +00002733void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
2734 ASSERT(ToRegister(instr->InputAt(0)).is(esi));
2735 __ push(esi); // The context is the first argument.
2736 __ push(Immediate(instr->hydrogen()->pairs()));
2737 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
2738 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
2739}
2740
2741
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002742void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2743 Register context = ToRegister(instr->context());
2744 Register result = ToRegister(instr->result());
2745 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002746}
2747
2748
2749void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002750 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002751 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002752 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002753}
2754
2755
2756void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2757 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002758 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00002759 CallKind call_kind,
2760 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002761 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
2762 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002763
2764 LPointerMap* pointers = instr->pointer_map();
2765 RecordPosition(pointers->position());
2766
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002767 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00002768 if (edi_state == EDI_UNINITIALIZED) {
2769 __ LoadHeapObject(edi, function);
2770 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002771
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002772 // Change context if needed.
2773 bool change_context =
2774 (info()->closure()->context() != function->context()) ||
2775 scope()->contains_with() ||
2776 (scope()->num_heap_slots() > 0);
2777
2778 if (change_context) {
2779 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
2780 } else {
2781 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2782 }
2783
2784 // Set eax to arguments count if adaption is not needed. Assumes that eax
2785 // is available to write to at this point.
2786 if (!function->NeedsArgumentsAdaption()) {
2787 __ mov(eax, arity);
2788 }
2789
2790 // Invoke function directly.
2791 __ SetCallKind(ecx, call_kind);
2792 if (*function == *info()->closure()) {
2793 __ CallSelf();
2794 } else {
2795 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2796 }
2797 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
2798 } else {
2799 // We need to adapt arguments.
2800 SafepointGenerator generator(
2801 this, pointers, Safepoint::kLazyDeopt);
2802 ParameterCount count(arity);
2803 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
2804 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002805}
2806
2807
2808void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2809 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002810 CallKnownFunction(instr->function(),
2811 instr->arity(),
2812 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00002813 CALL_AS_METHOD,
2814 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002815}
2816
2817
2818void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002819 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002820 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002822 DeoptimizeIf(not_equal, instr->environment());
2823
2824 Label done;
2825 Register tmp = input_reg.is(eax) ? ecx : eax;
2826 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2827
2828 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002829 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002830
2831 Label negative;
2832 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002833 // Check the sign of the argument. If the argument is positive, just
2834 // return it. We do not need to patch the stack since |input| and
2835 // |result| are the same register and |input| will be restored
2836 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002837 __ test(tmp, Immediate(HeapNumber::kSignMask));
2838 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002839 __ jmp(&done);
2840
2841 __ bind(&negative);
2842
2843 Label allocated, slow;
2844 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2845 __ jmp(&allocated);
2846
2847 // Slow case: Call the runtime system to do the number allocation.
2848 __ bind(&slow);
2849
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002850 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
2851 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002852
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002853 // Set the pointer to the new heap number in tmp.
2854 if (!tmp.is(eax)) __ mov(tmp, eax);
2855
2856 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002857 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002858
2859 __ bind(&allocated);
2860 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2861 __ and_(tmp2, ~HeapNumber::kSignMask);
2862 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2863 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2864 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002865 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002866
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002867 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002868}
2869
2870
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002871void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002872 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002873 __ test(input_reg, Operand(input_reg));
2874 Label is_positive;
2875 __ j(not_sign, &is_positive);
2876 __ neg(input_reg);
2877 __ test(input_reg, Operand(input_reg));
2878 DeoptimizeIf(negative, instr->environment());
2879 __ bind(&is_positive);
2880}
2881
2882
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002883void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2884 // Class for deferred case.
2885 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2886 public:
2887 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2888 LUnaryMathOperation* instr)
2889 : LDeferredCode(codegen), instr_(instr) { }
2890 virtual void Generate() {
2891 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2892 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002893 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002894 private:
2895 LUnaryMathOperation* instr_;
2896 };
2897
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002898 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002899 Representation r = instr->hydrogen()->value()->representation();
2900
2901 if (r.IsDouble()) {
2902 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002903 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002904 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002905 __ subsd(scratch, input_reg);
2906 __ pand(input_reg, scratch);
2907 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002908 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002909 } else { // Tagged case.
2910 DeferredMathAbsTaggedHeapNumber* deferred =
2911 new DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002912 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002913 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002914 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002915 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002916 __ bind(deferred->exit());
2917 }
2918}
2919
2920
2921void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2922 XMMRegister xmm_scratch = xmm0;
2923 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002924 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002925
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002926 if (CpuFeatures::IsSupported(SSE4_1)) {
2927 CpuFeatures::Scope scope(SSE4_1);
2928 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2929 // Deoptimize on negative zero.
2930 Label non_zero;
2931 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
2932 __ ucomisd(input_reg, xmm_scratch);
2933 __ j(not_equal, &non_zero, Label::kNear);
2934 __ movmskpd(output_reg, input_reg);
2935 __ test(output_reg, Immediate(1));
2936 DeoptimizeIf(not_zero, instr->environment());
2937 __ bind(&non_zero);
2938 }
2939 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
2940 __ cvttsd2si(output_reg, Operand(xmm_scratch));
2941 // Overflow is signalled with minint.
2942 __ cmp(output_reg, 0x80000000u);
2943 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 } else {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002945 Label negative_sign;
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002946 Label done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002947 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002948 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
2949 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002950 DeoptimizeIf(parity_even, instr->environment());
2951 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002952
2953 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2954 // Check for negative zero.
2955 Label positive_sign;
2956 __ j(above, &positive_sign, Label::kNear);
2957 __ movmskpd(output_reg, input_reg);
2958 __ test(output_reg, Immediate(1));
2959 DeoptimizeIf(not_zero, instr->environment());
2960 __ Set(output_reg, Immediate(0));
2961 __ jmp(&done, Label::kNear);
2962 __ bind(&positive_sign);
2963 }
2964
2965 // Use truncating instruction (OK because input is positive).
2966 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002967 // Overflow is signalled with minint.
2968 __ cmp(output_reg, 0x80000000u);
2969 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002970 __ jmp(&done, Label::kNear);
2971
2972 // Non-zero negative reaches here
2973 __ bind(&negative_sign);
2974 // Truncate, then compare and compensate
2975 __ cvttsd2si(output_reg, Operand(input_reg));
2976 __ cvtsi2sd(xmm_scratch, output_reg);
2977 __ ucomisd(input_reg, xmm_scratch);
2978 __ j(equal, &done, Label::kNear);
2979 __ sub(output_reg, Immediate(1));
2980 DeoptimizeIf(overflow, instr->environment());
2981
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002982 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002983 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002984}
2985
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002986void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2987 XMMRegister xmm_scratch = xmm0;
2988 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002989 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002990
danno@chromium.org160a7b02011-04-18 15:51:38 +00002991 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002992 // xmm_scratch = 0.5
2993 ExternalReference one_half = ExternalReference::address_of_one_half();
2994 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00002995 __ ucomisd(xmm_scratch, input_reg);
2996 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002997 // xmm_scratch = input + 0.5
2998 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002999
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003000 // Compute Math.floor(value + 0.5).
3001 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003002 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003003
3004 // Overflow is signalled with minint.
3005 __ cmp(output_reg, 0x80000000u);
3006 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003007 __ jmp(&done);
3008
3009 __ bind(&below_half);
3010
3011 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3012 // we can ignore the difference between a result of -0 and +0.
3013 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3014 // If the sign is positive, we return +0.
3015 __ movmskpd(output_reg, input_reg);
3016 __ test(output_reg, Immediate(1));
3017 DeoptimizeIf(not_zero, instr->environment());
3018 } else {
3019 // If the input is >= -0.5, we return +0.
3020 __ mov(output_reg, Immediate(0xBF000000));
3021 __ movd(xmm_scratch, Operand(output_reg));
3022 __ cvtss2sd(xmm_scratch, xmm_scratch);
3023 __ ucomisd(input_reg, xmm_scratch);
3024 DeoptimizeIf(below, instr->environment());
3025 }
3026 __ Set(output_reg, Immediate(0));
3027 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003028}
3029
3030
3031void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003032 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003033 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3034 __ sqrtsd(input_reg, input_reg);
3035}
3036
3037
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003038void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003039 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003040 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003041 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003042 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003043
3044 // Note that according to ECMA-262 15.8.2.13:
3045 // Math.pow(-Infinity, 0.5) == Infinity
3046 // Math.sqrt(-Infinity) == NaN
3047 Label done, sqrt;
3048 // Check base for -Infinity. According to IEEE-754, single-precision
3049 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3050 __ mov(scratch, 0xFF800000);
3051 __ movd(xmm_scratch, scratch);
3052 __ cvtss2sd(xmm_scratch, xmm_scratch);
3053 __ ucomisd(input_reg, xmm_scratch);
3054 // Comparing -Infinity with NaN results in "unordered", which sets the
3055 // zero flag as if both were equal. However, it also sets the carry flag.
3056 __ j(not_equal, &sqrt, Label::kNear);
3057 __ j(carry, &sqrt, Label::kNear);
3058 // If input is -Infinity, return Infinity.
3059 __ xorps(input_reg, input_reg);
3060 __ subsd(input_reg, xmm_scratch);
3061 __ jmp(&done, Label::kNear);
3062
3063 // Square root.
3064 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003065 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003066 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003067 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003068 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003069}
3070
3071
3072void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003073 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003074 // Having marked this as a call, we can use any registers.
3075 // Just make sure that the input/output registers are the expected ones.
3076 ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
3077 ToDoubleRegister(instr->InputAt(1)).is(xmm1));
3078 ASSERT(!instr->InputAt(1)->IsRegister() ||
3079 ToRegister(instr->InputAt(1)).is(eax));
3080 ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
3081 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003082
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003083 if (exponent_type.IsTagged()) {
3084 Label no_deopt;
3085 __ JumpIfSmi(eax, &no_deopt);
3086 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003087 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003088 __ bind(&no_deopt);
3089 MathPowStub stub(MathPowStub::TAGGED);
3090 __ CallStub(&stub);
3091 } else if (exponent_type.IsInteger32()) {
3092 MathPowStub stub(MathPowStub::INTEGER);
3093 __ CallStub(&stub);
3094 } else {
3095 ASSERT(exponent_type.IsDouble());
3096 MathPowStub stub(MathPowStub::DOUBLE);
3097 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003098 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003099}
3100
3101
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003102void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003103 class DeferredDoRandom: public LDeferredCode {
3104 public:
3105 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3106 : LDeferredCode(codegen), instr_(instr) { }
3107 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3108 virtual LInstruction* instr() { return instr_; }
3109 private:
3110 LRandom* instr_;
3111 };
3112
3113 DeferredDoRandom* deferred = new DeferredDoRandom(this, instr);
3114
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003115 // Having marked this instruction as a call we can use any
3116 // registers.
3117 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3118 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003119 // Assert that the register size is indeed the size of each seed.
3120 static const int kSeedSize = sizeof(uint32_t);
3121 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003122
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003123 __ mov(eax, FieldOperand(eax, GlobalObject::kGlobalContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003124 static const int kRandomSeedOffset =
3125 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3126 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
3127 // ebx: FixedArray of the global context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003128
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003129 // Load state[0].
3130 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3131 // If state[0] == 0, call runtime to initialize seeds.
3132 __ test(ecx, ecx);
3133 __ j(zero, deferred->entry());
3134 // Load state[1].
3135 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3136 // ecx: state[0]
3137 // eax: state[1]
3138
3139 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3140 __ movzx_w(edx, ecx);
3141 __ imul(edx, edx, 18273);
3142 __ shr(ecx, 16);
3143 __ add(ecx, edx);
3144 // Save state[0].
3145 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3146
3147 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3148 __ movzx_w(edx, eax);
3149 __ imul(edx, edx, 36969);
3150 __ shr(eax, 16);
3151 __ add(eax, edx);
3152 // Save state[1].
3153 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3154
3155 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3156 __ shl(ecx, 14);
3157 __ and_(eax, Immediate(0x3FFFF));
3158 __ add(eax, ecx);
3159
3160 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003161 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3162 // by computing:
3163 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3164 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3165 __ movd(xmm2, ebx);
3166 __ movd(xmm1, eax);
3167 __ cvtss2sd(xmm2, xmm2);
3168 __ xorps(xmm1, xmm2);
3169 __ subsd(xmm1, xmm2);
3170}
3171
3172
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003173void LCodeGen::DoDeferredRandom(LRandom* instr) {
3174 __ PrepareCallCFunction(1, ebx);
3175 __ mov(Operand(esp, 0), eax);
3176 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3177 // Return value is in eax.
3178}
3179
3180
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003181void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003182 ASSERT(instr->value()->Equals(instr->result()));
3183 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003184 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003185 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003186 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003187 __ j(above, &positive, Label::kNear);
3188 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003189 ExternalReference nan =
3190 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003191 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003192 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003193 __ bind(&zero);
3194 __ push(Immediate(0xFFF00000));
3195 __ push(Immediate(0));
3196 __ movdbl(input_reg, Operand(esp, 0));
3197 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003198 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003199 __ bind(&positive);
3200 __ fldln2();
3201 __ sub(Operand(esp), Immediate(kDoubleSize));
3202 __ movdbl(Operand(esp, 0), input_reg);
3203 __ fld_d(Operand(esp, 0));
3204 __ fyl2x();
3205 __ fstp_d(Operand(esp, 0));
3206 __ movdbl(input_reg, Operand(esp, 0));
3207 __ add(Operand(esp), Immediate(kDoubleSize));
3208 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003209}
3210
3211
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003212void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3213 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3214 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3215 TranscendentalCacheStub::UNTAGGED);
3216 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3217}
3218
3219
whesse@chromium.org023421e2010-12-21 12:19:12 +00003220void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3221 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3222 TranscendentalCacheStub stub(TranscendentalCache::COS,
3223 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003224 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003225}
3226
3227
3228void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3229 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3230 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3231 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003232 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003233}
3234
3235
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003236void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3237 switch (instr->op()) {
3238 case kMathAbs:
3239 DoMathAbs(instr);
3240 break;
3241 case kMathFloor:
3242 DoMathFloor(instr);
3243 break;
3244 case kMathRound:
3245 DoMathRound(instr);
3246 break;
3247 case kMathSqrt:
3248 DoMathSqrt(instr);
3249 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003250 case kMathCos:
3251 DoMathCos(instr);
3252 break;
3253 case kMathSin:
3254 DoMathSin(instr);
3255 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003256 case kMathTan:
3257 DoMathTan(instr);
3258 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003259 case kMathLog:
3260 DoMathLog(instr);
3261 break;
3262
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003263 default:
3264 UNREACHABLE();
3265 }
3266}
3267
3268
danno@chromium.org160a7b02011-04-18 15:51:38 +00003269void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3270 ASSERT(ToRegister(instr->context()).is(esi));
3271 ASSERT(ToRegister(instr->function()).is(edi));
3272 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003273
3274 if (instr->known_function().is_null()) {
3275 LPointerMap* pointers = instr->pointer_map();
3276 RecordPosition(pointers->position());
3277 SafepointGenerator generator(
3278 this, pointers, Safepoint::kLazyDeopt);
3279 ParameterCount count(instr->arity());
3280 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3281 } else {
3282 CallKnownFunction(instr->known_function(),
3283 instr->arity(),
3284 instr,
3285 CALL_AS_METHOD,
3286 EDI_CONTAINS_TARGET);
3287 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003288}
3289
3290
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003291void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003292 ASSERT(ToRegister(instr->context()).is(esi));
3293 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294 ASSERT(ToRegister(instr->result()).is(eax));
3295
3296 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003297 Handle<Code> ic =
3298 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003299 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003300}
3301
3302
3303void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003304 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003305 ASSERT(ToRegister(instr->result()).is(eax));
3306
3307 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003308 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3309 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003310 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003311 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003312 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003313}
3314
3315
3316void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003317 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003318 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003319 ASSERT(ToRegister(instr->result()).is(eax));
3320
3321 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003322 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003323 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003324}
3325
3326
3327void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003328 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003329 ASSERT(ToRegister(instr->result()).is(eax));
3330
3331 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003332 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3333 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003334 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003335 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003336 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003337}
3338
3339
3340void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3341 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003342 CallKnownFunction(instr->target(),
3343 instr->arity(),
3344 instr,
3345 CALL_AS_FUNCTION,
3346 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003347}
3348
3349
3350void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003351 ASSERT(ToRegister(instr->context()).is(esi));
3352 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003353 ASSERT(ToRegister(instr->result()).is(eax));
3354
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003355 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003356 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003357 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003358}
3359
3360
3361void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003362 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003363}
3364
3365
3366void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3367 Register object = ToRegister(instr->object());
3368 Register value = ToRegister(instr->value());
3369 int offset = instr->offset();
3370
3371 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00003372 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
3373 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3374 } else {
3375 Register temp = ToRegister(instr->TempAt(0));
3376 Register temp_map = ToRegister(instr->TempAt(1));
3377 __ mov(temp_map, instr->transition());
3378 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
3379 // Update the write barrier for the map field.
3380 __ RecordWriteField(object,
3381 HeapObject::kMapOffset,
3382 temp_map,
3383 temp,
3384 kSaveFPRegs,
3385 OMIT_REMEMBERED_SET,
3386 OMIT_SMI_CHECK);
3387 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003388 }
3389
3390 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003391 HType type = instr->hydrogen()->value()->type();
3392 SmiCheck check_needed =
3393 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003394 if (instr->is_in_object()) {
3395 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003396 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003397 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003398 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003399 __ RecordWriteField(object,
3400 offset,
3401 value,
3402 temp,
3403 kSaveFPRegs,
3404 EMIT_REMEMBERED_SET,
3405 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003406 }
3407 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003408 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003409 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3410 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003411 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003412 // Update the write barrier for the properties array.
3413 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003414 __ RecordWriteField(temp,
3415 offset,
3416 value,
3417 object,
3418 kSaveFPRegs,
3419 EMIT_REMEMBERED_SET,
3420 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003421 }
3422 }
3423}
3424
3425
3426void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003427 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003428 ASSERT(ToRegister(instr->object()).is(edx));
3429 ASSERT(ToRegister(instr->value()).is(eax));
3430
3431 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003432 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003433 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3434 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003435 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003436}
3437
3438
3439void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00003440 if (instr->index()->IsConstantOperand()) {
3441 __ cmp(ToOperand(instr->length()),
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00003442 Immediate(ToInteger32(LConstantOperand::cast(instr->index()))));
danno@chromium.orgb6451162011-08-17 14:33:23 +00003443 DeoptimizeIf(below_equal, instr->environment());
3444 } else {
3445 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3446 DeoptimizeIf(above_equal, instr->environment());
3447 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003448}
3449
3450
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003451void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3452 LStoreKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003453 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003454 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003455 instr->key(),
3456 elements_kind,
3457 0,
3458 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003459 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003460 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003461 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003462 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003463 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003464 } else {
3465 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003466 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003467 case EXTERNAL_PIXEL_ELEMENTS:
3468 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3469 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003470 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003471 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003472 case EXTERNAL_SHORT_ELEMENTS:
3473 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003474 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003475 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003476 case EXTERNAL_INT_ELEMENTS:
3477 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003478 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003479 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003480 case EXTERNAL_FLOAT_ELEMENTS:
3481 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003482 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003483 case FAST_ELEMENTS:
3484 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003485 case FAST_HOLEY_SMI_ELEMENTS:
3486 case FAST_HOLEY_ELEMENTS:
3487 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003488 case DICTIONARY_ELEMENTS:
3489 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003490 UNREACHABLE();
3491 break;
3492 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003493 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003494}
3495
3496
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003497void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3498 Register value = ToRegister(instr->value());
3499 Register elements = ToRegister(instr->object());
3500 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3501
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003502 Operand operand = BuildFastArrayOperand(
3503 instr->object(),
3504 instr->key(),
3505 FAST_ELEMENTS,
3506 FixedArray::kHeaderSize - kHeapObjectTag,
3507 instr->additional_index());
3508 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003509
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003510 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003511 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003512 HType type = instr->hydrogen()->value()->type();
3513 SmiCheck check_needed =
3514 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003515 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003516 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003517 __ RecordWrite(elements,
3518 key,
3519 value,
3520 kSaveFPRegs,
3521 EMIT_REMEMBERED_SET,
3522 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003523 }
3524}
3525
3526
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003527void LCodeGen::DoStoreKeyedFastDoubleElement(
3528 LStoreKeyedFastDoubleElement* instr) {
3529 XMMRegister value = ToDoubleRegister(instr->value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003530
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003531 if (instr->NeedsCanonicalization()) {
3532 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003533
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003534 __ ucomisd(value, value);
3535 __ j(parity_odd, &have_value); // NaN.
3536
3537 ExternalReference canonical_nan_reference =
3538 ExternalReference::address_of_canonical_non_hole_nan();
3539 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
3540 __ bind(&have_value);
3541 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003542
3543 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003544 instr->elements(),
3545 instr->key(),
3546 FAST_DOUBLE_ELEMENTS,
3547 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3548 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003549 __ movdbl(double_store_operand, value);
3550}
3551
3552
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003553void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003554 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003555 ASSERT(ToRegister(instr->object()).is(edx));
3556 ASSERT(ToRegister(instr->key()).is(ecx));
3557 ASSERT(ToRegister(instr->value()).is(eax));
3558
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003559 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003560 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3561 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003562 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003563}
3564
3565
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003566void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
3567 Register object_reg = ToRegister(instr->object());
3568 Register new_map_reg = ToRegister(instr->new_map_reg());
3569
3570 Handle<Map> from_map = instr->original_map();
3571 Handle<Map> to_map = instr->transitioned_map();
3572 ElementsKind from_kind = from_map->elements_kind();
3573 ElementsKind to_kind = to_map->elements_kind();
3574
3575 Label not_applicable;
3576 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
3577 __ j(not_equal, &not_applicable);
3578 __ mov(new_map_reg, to_map);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003579 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003580 Register object_reg = ToRegister(instr->object());
3581 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
3582 // Write barrier.
3583 ASSERT_NE(instr->temp_reg(), NULL);
3584 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
3585 ToRegister(instr->temp_reg()), kDontSaveFPRegs);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003586 } else if (IsFastSmiElementsKind(from_kind) &&
3587 IsFastDoubleElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003588 Register fixed_object_reg = ToRegister(instr->temp_reg());
3589 ASSERT(fixed_object_reg.is(edx));
3590 ASSERT(new_map_reg.is(ebx));
3591 __ mov(fixed_object_reg, object_reg);
3592 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
3593 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003594 } else if (IsFastDoubleElementsKind(from_kind) &&
3595 IsFastObjectElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003596 Register fixed_object_reg = ToRegister(instr->temp_reg());
3597 ASSERT(fixed_object_reg.is(edx));
3598 ASSERT(new_map_reg.is(ebx));
3599 __ mov(fixed_object_reg, object_reg);
3600 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
3601 RelocInfo::CODE_TARGET, instr);
3602 } else {
3603 UNREACHABLE();
3604 }
3605 __ bind(&not_applicable);
3606}
3607
3608
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003609void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3610 class DeferredStringCharCodeAt: public LDeferredCode {
3611 public:
3612 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3613 : LDeferredCode(codegen), instr_(instr) { }
3614 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003615 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003616 private:
3617 LStringCharCodeAt* instr_;
3618 };
3619
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003620 DeferredStringCharCodeAt* deferred =
3621 new DeferredStringCharCodeAt(this, instr);
3622
erikcorry0ad885c2011-11-21 13:51:57 +00003623 StringCharLoadGenerator::Generate(masm(),
3624 factory(),
3625 ToRegister(instr->string()),
3626 ToRegister(instr->index()),
3627 ToRegister(instr->result()),
3628 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003629 __ bind(deferred->exit());
3630}
3631
3632
3633void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3634 Register string = ToRegister(instr->string());
3635 Register result = ToRegister(instr->result());
3636
3637 // TODO(3095996): Get rid of this. For now, we need to make the
3638 // result register contain a valid pointer because it is already
3639 // contained in the register pointer map.
3640 __ Set(result, Immediate(0));
3641
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003642 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003643 __ push(string);
3644 // Push the index as a smi. This is safe because of the checks in
3645 // DoStringCharCodeAt above.
3646 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3647 if (instr->index()->IsConstantOperand()) {
3648 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3649 __ push(Immediate(Smi::FromInt(const_index)));
3650 } else {
3651 Register index = ToRegister(instr->index());
3652 __ SmiTag(index);
3653 __ push(index);
3654 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003655 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
3656 instr, instr->context());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003657 if (FLAG_debug_code) {
3658 __ AbortIfNotSmi(eax);
3659 }
3660 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003661 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003662}
3663
3664
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003665void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3666 class DeferredStringCharFromCode: public LDeferredCode {
3667 public:
3668 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3669 : LDeferredCode(codegen), instr_(instr) { }
3670 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003671 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003672 private:
3673 LStringCharFromCode* instr_;
3674 };
3675
3676 DeferredStringCharFromCode* deferred =
3677 new DeferredStringCharFromCode(this, instr);
3678
3679 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3680 Register char_code = ToRegister(instr->char_code());
3681 Register result = ToRegister(instr->result());
3682 ASSERT(!char_code.is(result));
3683
3684 __ cmp(char_code, String::kMaxAsciiCharCode);
3685 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003686 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003687 __ mov(result, FieldOperand(result,
3688 char_code, times_pointer_size,
3689 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003691 __ j(equal, deferred->entry());
3692 __ bind(deferred->exit());
3693}
3694
3695
3696void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3697 Register char_code = ToRegister(instr->char_code());
3698 Register result = ToRegister(instr->result());
3699
3700 // TODO(3095996): Get rid of this. For now, we need to make the
3701 // result register contain a valid pointer because it is already
3702 // contained in the register pointer map.
3703 __ Set(result, Immediate(0));
3704
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003705 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003706 __ SmiTag(char_code);
3707 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003708 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003709 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003710}
3711
3712
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003713void LCodeGen::DoStringLength(LStringLength* instr) {
3714 Register string = ToRegister(instr->string());
3715 Register result = ToRegister(instr->result());
3716 __ mov(result, FieldOperand(string, String::kLengthOffset));
3717}
3718
3719
danno@chromium.org160a7b02011-04-18 15:51:38 +00003720void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003721 EmitPushTaggedOperand(instr->left());
3722 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003723 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003724 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003725}
3726
3727
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003728void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003729 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003730 ASSERT(input->IsRegister() || input->IsStackSlot());
3731 LOperand* output = instr->result();
3732 ASSERT(output->IsDoubleRegister());
3733 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3734}
3735
3736
3737void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3738 class DeferredNumberTagI: public LDeferredCode {
3739 public:
3740 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3741 : LDeferredCode(codegen), instr_(instr) { }
3742 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003743 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003744 private:
3745 LNumberTagI* instr_;
3746 };
3747
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003748 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003749 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3750 Register reg = ToRegister(input);
3751
3752 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3753 __ SmiTag(reg);
3754 __ j(overflow, deferred->entry());
3755 __ bind(deferred->exit());
3756}
3757
3758
3759void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3760 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003761 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003762 Register tmp = reg.is(eax) ? ecx : eax;
3763
3764 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003765 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003766
3767 // There was overflow, so bits 30 and 31 of the original integer
3768 // disagree. Try to allocate a heap number in new space and store
3769 // the value in there. If that fails, call the runtime system.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003770 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003771 __ SmiUntag(reg);
3772 __ xor_(reg, 0x80000000);
3773 __ cvtsi2sd(xmm0, Operand(reg));
3774 if (FLAG_inline_new) {
3775 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003776 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003777 }
3778
3779 // Slow case: Call the runtime system to do the number allocation.
3780 __ bind(&slow);
3781
3782 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3783 // register is stored, as this register is in the pointer map, but contains an
3784 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003785 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003786 // NumberTagI and NumberTagD use the context from the frame, rather than
3787 // the environment's HContext or HInlinedContext value.
3788 // They only call Runtime::kAllocateHeapNumber.
3789 // The corresponding HChange instructions are added in a phase that does
3790 // not have easy access to the local context.
3791 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3792 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3793 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003794 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003795 if (!reg.is(eax)) __ mov(reg, eax);
3796
3797 // Done. Put the value in xmm0 into the value of the allocated heap
3798 // number.
3799 __ bind(&done);
3800 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003801 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003802}
3803
3804
3805void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3806 class DeferredNumberTagD: public LDeferredCode {
3807 public:
3808 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3809 : LDeferredCode(codegen), instr_(instr) { }
3810 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003811 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003812 private:
3813 LNumberTagD* instr_;
3814 };
3815
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003816 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003817 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003818 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003819
3820 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3821 if (FLAG_inline_new) {
3822 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3823 } else {
3824 __ jmp(deferred->entry());
3825 }
3826 __ bind(deferred->exit());
3827 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3828}
3829
3830
3831void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3832 // TODO(3095996): Get rid of this. For now, we need to make the
3833 // result register contain a valid pointer because it is already
3834 // contained in the register pointer map.
3835 Register reg = ToRegister(instr->result());
3836 __ Set(reg, Immediate(0));
3837
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003838 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003839 // NumberTagI and NumberTagD use the context from the frame, rather than
3840 // the environment's HContext or HInlinedContext value.
3841 // They only call Runtime::kAllocateHeapNumber.
3842 // The corresponding HChange instructions are added in a phase that does
3843 // not have easy access to the local context.
3844 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3845 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003846 RecordSafepointWithRegisters(
3847 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003848 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003849}
3850
3851
3852void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003853 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003854 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3855 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3856 __ SmiTag(ToRegister(input));
3857}
3858
3859
3860void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003861 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003862 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3863 if (instr->needs_check()) {
3864 __ test(ToRegister(input), Immediate(kSmiTagMask));
3865 DeoptimizeIf(not_zero, instr->environment());
3866 }
3867 __ SmiUntag(ToRegister(input));
3868}
3869
3870
3871void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003872 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003873 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003874 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003875 bool deoptimize_on_minus_zero,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003876 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003877 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003878
3879 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003880 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003881
3882 // Heap number map check.
3883 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003885 if (deoptimize_on_undefined) {
3886 DeoptimizeIf(not_equal, env);
3887 } else {
3888 Label heap_number;
3889 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003890
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003891 __ cmp(input_reg, factory()->undefined_value());
3892 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003893
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003894 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003895 ExternalReference nan =
3896 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003897 __ movdbl(result_reg, Operand::StaticVariable(nan));
3898 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003899
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003900 __ bind(&heap_number);
3901 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003902 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003903 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003904 if (deoptimize_on_minus_zero) {
3905 XMMRegister xmm_scratch = xmm0;
3906 __ xorps(xmm_scratch, xmm_scratch);
3907 __ ucomisd(result_reg, xmm_scratch);
3908 __ j(not_zero, &done, Label::kNear);
3909 __ movmskpd(temp_reg, result_reg);
3910 __ test_b(temp_reg, 1);
3911 DeoptimizeIf(not_zero, env);
3912 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003913 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003914
3915 // Smi to XMM conversion
3916 __ bind(&load_smi);
3917 __ SmiUntag(input_reg); // Untag smi before converting to float.
3918 __ cvtsi2sd(result_reg, Operand(input_reg));
3919 __ SmiTag(input_reg); // Retag smi.
3920 __ bind(&done);
3921}
3922
3923
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003924void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003925 Label done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003926 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003927
3928 // Heap number map check.
3929 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003931
3932 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003933 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003934 // Check for undefined. Undefined is converted to zero for truncating
3935 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003937 DeoptimizeIf(not_equal, instr->environment());
3938 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003939 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003940
3941 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003942 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003943 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003944 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003945 // Use more powerful conversion when sse3 is available.
3946 // Load x87 register with heap number.
3947 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3948 // Get exponent alone and check for too-big exponent.
3949 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3950 __ and_(input_reg, HeapNumber::kExponentMask);
3951 const uint32_t kTooBigExponent =
3952 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3953 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003954 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003955 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003956 __ fstp(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003957 DeoptimizeIf(no_condition, instr->environment());
3958
3959 // Reserve space for 64 bit answer.
3960 __ bind(&convert);
3961 __ sub(Operand(esp), Immediate(kDoubleSize));
3962 // Do conversion, which cannot fail because we checked the exponent.
3963 __ fisttp_d(Operand(esp, 0));
3964 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3965 __ add(Operand(esp), Immediate(kDoubleSize));
3966 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003967 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003968 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3969 __ cvttsd2si(input_reg, Operand(xmm0));
3970 __ cmp(input_reg, 0x80000000u);
3971 __ j(not_equal, &done);
3972 // Check if the input was 0x8000000 (kMinInt).
3973 // If no, then we got an overflow and we deoptimize.
3974 ExternalReference min_int = ExternalReference::address_of_min_int();
3975 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3976 __ ucomisd(xmm_temp, xmm0);
3977 DeoptimizeIf(not_equal, instr->environment());
3978 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3979 }
3980 } else {
3981 // Deoptimize if we don't have a heap number.
3982 DeoptimizeIf(not_equal, instr->environment());
3983
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003984 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003985 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3986 __ cvttsd2si(input_reg, Operand(xmm0));
3987 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3988 __ ucomisd(xmm0, xmm_temp);
3989 DeoptimizeIf(not_equal, instr->environment());
3990 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3991 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3992 __ test(input_reg, Operand(input_reg));
3993 __ j(not_zero, &done);
3994 __ movmskpd(input_reg, xmm0);
3995 __ and_(input_reg, 1);
3996 DeoptimizeIf(not_zero, instr->environment());
3997 }
3998 }
3999 __ bind(&done);
4000}
4001
4002
4003void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004004 class DeferredTaggedToI: public LDeferredCode {
4005 public:
4006 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4007 : LDeferredCode(codegen), instr_(instr) { }
4008 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4009 virtual LInstruction* instr() { return instr_; }
4010 private:
4011 LTaggedToI* instr_;
4012 };
4013
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004014 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004015 ASSERT(input->IsRegister());
4016 ASSERT(input->Equals(instr->result()));
4017
4018 Register input_reg = ToRegister(input);
4019
4020 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
4021
4022 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004023 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004024
4025 // Smi to int32 conversion
4026 __ SmiUntag(input_reg); // Untag smi.
4027
4028 __ bind(deferred->exit());
4029}
4030
4031
4032void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004033 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004034 ASSERT(input->IsRegister());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004035 LOperand* temp = instr->TempAt(0);
4036 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004037 LOperand* result = instr->result();
4038 ASSERT(result->IsDoubleRegister());
4039
4040 Register input_reg = ToRegister(input);
4041 XMMRegister result_reg = ToDoubleRegister(result);
4042
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004043 bool deoptimize_on_minus_zero =
4044 instr->hydrogen()->deoptimize_on_minus_zero();
4045 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
4046
4047 EmitNumberUntagD(input_reg,
4048 temp_reg,
4049 result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004050 instr->hydrogen()->deoptimize_on_undefined(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004051 deoptimize_on_minus_zero,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004052 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004053}
4054
4055
4056void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004057 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004058 ASSERT(input->IsDoubleRegister());
4059 LOperand* result = instr->result();
4060 ASSERT(result->IsRegister());
4061
4062 XMMRegister input_reg = ToDoubleRegister(input);
4063 Register result_reg = ToRegister(result);
4064
4065 if (instr->truncating()) {
4066 // Performs a truncating conversion of a floating point number as used by
4067 // the JS bitwise operations.
4068 __ cvttsd2si(result_reg, Operand(input_reg));
4069 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004070 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004071 // This will deoptimize if the exponent of the input in out of range.
4072 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004073 Label convert, done;
4074 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004075 __ sub(Operand(esp), Immediate(kDoubleSize));
4076 __ movdbl(Operand(esp, 0), input_reg);
4077 // Get exponent alone and check for too-big exponent.
4078 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
4079 __ and_(result_reg, HeapNumber::kExponentMask);
4080 const uint32_t kTooBigExponent =
4081 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4082 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004083 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004084 __ add(Operand(esp), Immediate(kDoubleSize));
4085 DeoptimizeIf(no_condition, instr->environment());
4086 __ bind(&convert);
4087 // Do conversion, which cannot fail because we checked the exponent.
4088 __ fld_d(Operand(esp, 0));
4089 __ fisttp_d(Operand(esp, 0));
4090 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
4091 __ add(Operand(esp), Immediate(kDoubleSize));
4092 __ bind(&done);
4093 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004094 Label done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004095 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004096 XMMRegister xmm_scratch = xmm0;
4097
4098 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
4099 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004100 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004101
4102 // Get high 32 bits of the input in result_reg and temp_reg.
4103 __ pshufd(xmm_scratch, input_reg, 1);
4104 __ movd(Operand(temp_reg), xmm_scratch);
4105 __ mov(result_reg, temp_reg);
4106
4107 // Prepare negation mask in temp_reg.
4108 __ sar(temp_reg, kBitsPerInt - 1);
4109
4110 // Extract the exponent from result_reg and subtract adjusted
4111 // bias from it. The adjustment is selected in a way such that
4112 // when the difference is zero, the answer is in the low 32 bits
4113 // of the input, otherwise a shift has to be performed.
4114 __ shr(result_reg, HeapNumber::kExponentShift);
4115 __ and_(result_reg,
4116 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
4117 __ sub(Operand(result_reg),
4118 Immediate(HeapNumber::kExponentBias +
4119 HeapNumber::kExponentBits +
4120 HeapNumber::kMantissaBits));
4121 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
4122 // special exponents.
4123 DeoptimizeIf(greater, instr->environment());
4124
4125 // Zero out the sign and the exponent in the input (by shifting
4126 // it to the left) and restore the implicit mantissa bit,
4127 // i.e. convert the input to unsigned int64 shifted left by
4128 // kExponentBits.
4129 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
4130 // Minus zero has the most significant bit set and the other
4131 // bits cleared.
4132 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
4133 __ psllq(input_reg, HeapNumber::kExponentBits);
4134 __ por(input_reg, xmm_scratch);
4135
4136 // Get the amount to shift the input right in xmm_scratch.
4137 __ neg(result_reg);
4138 __ movd(xmm_scratch, Operand(result_reg));
4139
4140 // Shift the input right and extract low 32 bits.
4141 __ psrlq(input_reg, xmm_scratch);
4142 __ movd(Operand(result_reg), input_reg);
4143
4144 // Use the prepared mask in temp_reg to negate the result if necessary.
4145 __ xor_(result_reg, Operand(temp_reg));
4146 __ sub(result_reg, Operand(temp_reg));
4147 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004148 }
4149 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004150 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004151 __ cvttsd2si(result_reg, Operand(input_reg));
4152 __ cvtsi2sd(xmm0, Operand(result_reg));
4153 __ ucomisd(xmm0, input_reg);
4154 DeoptimizeIf(not_equal, instr->environment());
4155 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4156 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4157 // The integer converted back is equal to the original. We
4158 // only have to test if we got -0 as an input.
4159 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004160 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004161 __ movmskpd(result_reg, input_reg);
4162 // Bit 0 contains the sign of the double in input_reg.
4163 // If input was positive, we are ok and return 0, otherwise
4164 // deoptimize.
4165 __ and_(result_reg, 1);
4166 DeoptimizeIf(not_zero, instr->environment());
4167 }
4168 __ bind(&done);
4169 }
4170}
4171
4172
4173void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004174 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004175 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004176 DeoptimizeIf(not_zero, instr->environment());
4177}
4178
4179
4180void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
4181 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004182 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004183 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004184}
4185
4186
4187void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004188 Register input = ToRegister(instr->InputAt(0));
4189 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004190
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004191 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004193 if (instr->hydrogen()->is_interval_check()) {
4194 InstanceType first;
4195 InstanceType last;
4196 instr->hydrogen()->GetCheckInterval(&first, &last);
4197
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004198 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4199 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004200
4201 // If there is only one type in the interval check for equality.
4202 if (first == last) {
4203 DeoptimizeIf(not_equal, instr->environment());
4204 } else {
4205 DeoptimizeIf(below, instr->environment());
4206 // Omit check for the last type.
4207 if (last != LAST_TYPE) {
4208 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4209 static_cast<int8_t>(last));
4210 DeoptimizeIf(above, instr->environment());
4211 }
4212 }
4213 } else {
4214 uint8_t mask;
4215 uint8_t tag;
4216 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4217
4218 if (IsPowerOf2(mask)) {
4219 ASSERT(tag == 0 || IsPowerOf2(tag));
4220 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
4221 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4222 } else {
4223 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4224 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004225 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004226 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004227 }
4228 }
4229}
4230
4231
4232void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004233 Handle<JSFunction> target = instr->hydrogen()->target();
4234 if (isolate()->heap()->InNewSpace(*target)) {
4235 Register reg = ToRegister(instr->value());
4236 Handle<JSGlobalPropertyCell> cell =
4237 isolate()->factory()->NewJSGlobalPropertyCell(target);
4238 __ cmp(reg, Operand::Cell(cell));
4239 } else {
4240 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004241 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004242 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004243 DeoptimizeIf(not_equal, instr->environment());
4244}
4245
4246
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004247void LCodeGen::DoCheckMapCommon(Register reg,
4248 Handle<Map> map,
4249 CompareMapMode mode,
4250 LEnvironment* env) {
4251 Label success;
4252 __ CompareMap(reg, map, &success, mode);
4253 DeoptimizeIf(not_equal, env);
4254 __ bind(&success);
4255}
4256
4257
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004258void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004259 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004260 ASSERT(input->IsRegister());
4261 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004262
4263 Label success;
4264 SmallMapList* map_set = instr->hydrogen()->map_set();
4265 for (int i = 0; i < map_set->length() - 1; i++) {
4266 Handle<Map> map = map_set->at(i);
4267 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
4268 __ j(equal, &success);
4269 }
4270 Handle<Map> map = map_set->last();
4271 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
4272 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004273}
4274
4275
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004276void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4277 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4278 Register result_reg = ToRegister(instr->result());
4279 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4280}
4281
4282
4283void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4284 ASSERT(instr->unclamped()->Equals(instr->result()));
4285 Register value_reg = ToRegister(instr->result());
4286 __ ClampUint8(value_reg);
4287}
4288
4289
4290void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4291 ASSERT(instr->unclamped()->Equals(instr->result()));
4292 Register input_reg = ToRegister(instr->unclamped());
4293 Label is_smi, done, heap_number;
4294
4295 __ JumpIfSmi(input_reg, &is_smi);
4296
4297 // Check for heap number
4298 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4299 factory()->heap_number_map());
4300 __ j(equal, &heap_number, Label::kNear);
4301
4302 // Check for undefined. Undefined is converted to zero for clamping
4303 // conversions.
4304 __ cmp(input_reg, factory()->undefined_value());
4305 DeoptimizeIf(not_equal, instr->environment());
4306 __ mov(input_reg, 0);
4307 __ jmp(&done, Label::kNear);
4308
4309 // Heap number
4310 __ bind(&heap_number);
4311 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4312 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4313 __ jmp(&done, Label::kNear);
4314
4315 // smi
4316 __ bind(&is_smi);
4317 __ SmiUntag(input_reg);
4318 __ ClampUint8(input_reg);
4319
4320 __ bind(&done);
4321}
4322
4323
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004324void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004325 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004326
4327 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004328 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004329
4330 // Load prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004331 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004332
4333 // Check prototype maps up to the holder.
4334 while (!current_prototype.is_identical_to(holder)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004335 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4336 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4337
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004338 current_prototype =
4339 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4340 // Load next prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004341 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004342 }
4343
4344 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004345 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4346 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004347}
4348
4349
ulan@chromium.org967e2702012-02-28 09:49:15 +00004350void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
4351 class DeferredAllocateObject: public LDeferredCode {
4352 public:
4353 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
4354 : LDeferredCode(codegen), instr_(instr) { }
4355 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
4356 virtual LInstruction* instr() { return instr_; }
4357 private:
4358 LAllocateObject* instr_;
4359 };
4360
4361 DeferredAllocateObject* deferred = new DeferredAllocateObject(this, instr);
4362
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004363 Register result = ToRegister(instr->result());
4364 Register scratch = ToRegister(instr->TempAt(0));
4365 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4366 Handle<Map> initial_map(constructor->initial_map());
4367 int instance_size = initial_map->instance_size();
4368 ASSERT(initial_map->pre_allocated_property_fields() +
4369 initial_map->unused_property_fields() -
4370 initial_map->inobject_properties() == 0);
4371
4372 // Allocate memory for the object. The initial map might change when
4373 // the constructor's prototype changes, but instance size and property
4374 // counts remain unchanged (if slack tracking finished).
4375 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
4376 __ AllocateInNewSpace(instance_size,
4377 result,
4378 no_reg,
4379 scratch,
4380 deferred->entry(),
4381 TAG_OBJECT);
4382
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004383 __ bind(deferred->exit());
4384 if (FLAG_debug_code) {
4385 Label is_in_new_space;
4386 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
4387 __ Abort("Allocated object is not in new-space");
4388 __ bind(&is_in_new_space);
4389 }
4390
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004391 // Load the initial map.
4392 Register map = scratch;
4393 __ LoadHeapObject(scratch, constructor);
4394 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
4395
4396 if (FLAG_debug_code) {
4397 __ AbortIfSmi(map);
4398 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
4399 instance_size >> kPointerSizeLog2);
4400 __ Assert(equal, "Unexpected instance size");
4401 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
4402 initial_map->pre_allocated_property_fields());
4403 __ Assert(equal, "Unexpected pre-allocated property fields count");
4404 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
4405 initial_map->unused_property_fields());
4406 __ Assert(equal, "Unexpected unused property fields count");
4407 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
4408 initial_map->inobject_properties());
4409 __ Assert(equal, "Unexpected in-object property fields count");
4410 }
4411
4412 // Initialize map and fields of the newly allocated object.
4413 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
4414 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
4415 __ mov(scratch, factory()->empty_fixed_array());
4416 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
4417 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
4418 if (initial_map->inobject_properties() != 0) {
4419 __ mov(scratch, factory()->undefined_value());
4420 for (int i = 0; i < initial_map->inobject_properties(); i++) {
4421 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
4422 __ mov(FieldOperand(result, property_offset), scratch);
4423 }
4424 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00004425}
4426
4427
4428void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
4429 Register result = ToRegister(instr->result());
4430 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004431 Handle<Map> initial_map(constructor->initial_map());
4432 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00004433
4434 // TODO(3095996): Get rid of this. For now, we need to make the
4435 // result register contain a valid pointer because it is already
4436 // contained in the register pointer map.
4437 __ Set(result, Immediate(0));
4438
4439 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004440 __ push(Immediate(Smi::FromInt(instance_size)));
4441 CallRuntimeFromDeferred(
4442 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00004443 __ StoreToSafepointRegisterSlot(result, eax);
4444}
4445
4446
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004447void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004448 ASSERT(ToRegister(instr->context()).is(esi));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004449 Heap* heap = isolate()->heap();
4450 ElementsKind boilerplate_elements_kind =
4451 instr->hydrogen()->boilerplate_elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004452
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004453 // Deopt if the array literal boilerplate ElementsKind is of a type different
4454 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004455 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
4456 if (CanTransitionToMoreGeneralFastElementsKind(
4457 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004458 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
4459 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
4460 // Load the map's "bit field 2". We only need the first byte,
4461 // but the following masking takes care of that anyway.
4462 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
4463 // Retrieve elements_kind from bit field 2.
4464 __ and_(ebx, Map::kElementsKindMask);
4465 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
4466 DeoptimizeIf(not_equal, instr->environment());
4467 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004468
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004469 // Set up the parameters to the stub/runtime call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004470 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4471 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
4472 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004473 // Boilerplate already exists, constant elements are never accessed.
4474 // Pass an empty fixed array.
4475 __ push(Immediate(Handle<FixedArray>(heap->empty_fixed_array())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004476
4477 // Pick the right runtime function or stub to call.
4478 int length = instr->hydrogen()->length();
4479 if (instr->hydrogen()->IsCopyOnWrite()) {
4480 ASSERT(instr->hydrogen()->depth() == 1);
4481 FastCloneShallowArrayStub::Mode mode =
4482 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4483 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004484 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004485 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004486 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004487 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004488 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004489 } else {
4490 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004491 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
4492 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4493 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004494 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004495 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004496 }
4497}
4498
4499
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004500void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
4501 Register result,
4502 Register source,
4503 int* offset) {
4504 ASSERT(!source.is(ecx));
4505 ASSERT(!result.is(ecx));
4506
4507 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004508 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004509 __ cmp(source, ecx);
4510 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00004511 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
4512 __ cmp(ecx, Handle<Map>(object->map()));
4513 __ Assert(equal, "Unexpected boilerplate map");
4514 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
4515 __ and_(ecx, Map::kElementsKindMask);
4516 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
4517 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004518 }
4519
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004520 // Only elements backing stores for non-COW arrays need to be copied.
4521 Handle<FixedArrayBase> elements(object->elements());
4522 bool has_elements = elements->length() > 0 &&
4523 elements->map() != isolate()->heap()->fixed_cow_array_map();
4524
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004525 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004526 // this object and its backing store.
4527 int object_offset = *offset;
4528 int object_size = object->map()->instance_size();
4529 int elements_offset = *offset + object_size;
4530 int elements_size = has_elements ? elements->Size() : 0;
4531 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004532
4533 // Copy object header.
4534 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004535 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004536 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004537 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004538 if (has_elements && i == JSObject::kElementsOffset) {
4539 __ lea(ecx, Operand(result, elements_offset));
4540 } else {
4541 __ mov(ecx, FieldOperand(source, i));
4542 }
4543 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004544 }
4545
4546 // Copy in-object properties.
4547 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004548 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004549 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
4550 if (value->IsJSObject()) {
4551 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4552 __ lea(ecx, Operand(result, *offset));
4553 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004554 __ LoadHeapObject(source, value_object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004555 EmitDeepCopy(value_object, result, source, offset);
4556 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004557 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004558 __ mov(FieldOperand(result, total_offset), ecx);
4559 } else {
4560 __ mov(FieldOperand(result, total_offset), Immediate(value));
4561 }
4562 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004563
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004564 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004565 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004566 __ LoadHeapObject(source, elements);
4567 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
4568 __ mov(ecx, FieldOperand(source, i));
4569 __ mov(FieldOperand(result, elements_offset + i), ecx);
4570 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004571
danno@chromium.org88aa0582012-03-23 15:11:57 +00004572 // Copy elements backing store content.
4573 int elements_length = elements->length();
4574 if (elements->IsFixedDoubleArray()) {
4575 Handle<FixedDoubleArray> double_array =
4576 Handle<FixedDoubleArray>::cast(elements);
4577 for (int i = 0; i < elements_length; i++) {
4578 int64_t value = double_array->get_representation(i);
4579 int32_t value_low = value & 0xFFFFFFFF;
4580 int32_t value_high = value >> 32;
4581 int total_offset =
4582 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
4583 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
4584 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
4585 }
4586 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004587 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004588 for (int i = 0; i < elements_length; i++) {
4589 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004590 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00004591 if (value->IsJSObject()) {
4592 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4593 __ lea(ecx, Operand(result, *offset));
4594 __ mov(FieldOperand(result, total_offset), ecx);
4595 __ LoadHeapObject(source, value_object);
4596 EmitDeepCopy(value_object, result, source, offset);
4597 } else if (value->IsHeapObject()) {
4598 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
4599 __ mov(FieldOperand(result, total_offset), ecx);
4600 } else {
4601 __ mov(FieldOperand(result, total_offset), Immediate(value));
4602 }
4603 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004604 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004605 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004606 }
4607 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004608}
4609
4610
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004611void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004612 ASSERT(ToRegister(instr->context()).is(esi));
4613 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00004614 ElementsKind boilerplate_elements_kind =
4615 instr->hydrogen()->boilerplate()->GetElementsKind();
4616
4617 // Deopt if the literal boilerplate ElementsKind is of a type different than
4618 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004619 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
4620 if (CanTransitionToMoreGeneralFastElementsKind(
4621 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00004622 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
4623 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
4624 // Load the map's "bit field 2". We only need the first byte,
4625 // but the following masking takes care of that anyway.
4626 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
4627 // Retrieve elements_kind from bit field 2.
4628 __ and_(ecx, Map::kElementsKindMask);
4629 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
4630 DeoptimizeIf(not_equal, instr->environment());
4631 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004632
4633 // Allocate all objects that are part of the literal in one big
4634 // allocation. This avoids multiple limit checks.
4635 Label allocated, runtime_allocate;
4636 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
4637 __ jmp(&allocated);
4638
4639 __ bind(&runtime_allocate);
4640 __ push(Immediate(Smi::FromInt(size)));
4641 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
4642
4643 __ bind(&allocated);
4644 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004645 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004646 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset);
4647 ASSERT_EQ(size, offset);
4648}
4649
4650
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004651void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004652 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004653 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004654 Handle<FixedArray> constant_properties =
4655 instr->hydrogen()->constant_properties();
4656
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004657 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004658 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004659 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004660 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 int flags = instr->hydrogen()->fast_elements()
4662 ? ObjectLiteral::kFastElements
4663 : ObjectLiteral::kNoFlags;
4664 flags |= instr->hydrogen()->has_function()
4665 ? ObjectLiteral::kHasFunction
4666 : ObjectLiteral::kNoFlags;
4667 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004668
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004669 // Pick the right runtime function or stub to call.
4670 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004671 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004672 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004673 } else if (flags != ObjectLiteral::kFastElements ||
4674 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004675 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004676 } else {
4677 FastCloneShallowObjectStub stub(properties_count);
4678 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004679 }
4680}
4681
4682
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
4684 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
4685 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004686 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004687}
4688
4689
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004690void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004691 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004692 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004693 // Registers will be used as follows:
4694 // edi = JS function.
4695 // ecx = literals array.
4696 // ebx = regexp literal.
4697 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004698 // esi = context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004699 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4700 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
4701 int literal_offset = FixedArray::kHeaderSize +
4702 instr->hydrogen()->literal_index() * kPointerSize;
4703 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004705 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004706
4707 // Create regexp literal using runtime function
4708 // Result will be in eax.
4709 __ push(ecx);
4710 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
4711 __ push(Immediate(instr->hydrogen()->pattern()));
4712 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004713 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004714 __ mov(ebx, eax);
4715
4716 __ bind(&materialized);
4717 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
4718 Label allocated, runtime_allocate;
4719 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
4720 __ jmp(&allocated);
4721
4722 __ bind(&runtime_allocate);
4723 __ push(ebx);
4724 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004725 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004726 __ pop(ebx);
4727
4728 __ bind(&allocated);
4729 // Copy the content into the newly allocated memory.
4730 // (Unroll copy loop once for better throughput).
4731 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4732 __ mov(edx, FieldOperand(ebx, i));
4733 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
4734 __ mov(FieldOperand(eax, i), edx);
4735 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
4736 }
4737 if ((size % (2 * kPointerSize)) != 0) {
4738 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
4739 __ mov(FieldOperand(eax, size - kPointerSize), edx);
4740 }
4741}
4742
4743
4744void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004745 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004746 // Use the fast case closure allocation code that allocates in new
4747 // space for nested functions that don't need literals cloning.
4748 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004749 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004751 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004752 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004753 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004754 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00004755 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004756 __ push(Immediate(shared_info));
4757 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004758 ? factory()->true_value()
4759 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004760 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004761 }
4762}
4763
4764
4765void LCodeGen::DoTypeof(LTypeof* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004766 LOperand* input = instr->InputAt(1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004767 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004768 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004769}
4770
4771
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004772void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004773 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004774 int true_block = chunk_->LookupDestination(instr->true_block_id());
4775 int false_block = chunk_->LookupDestination(instr->false_block_id());
4776 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4777 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4778
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004779 Condition final_branch_condition =
4780 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
4781 if (final_branch_condition != no_condition) {
4782 EmitBranch(true_block, false_block, final_branch_condition);
4783 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004784}
4785
4786
4787Condition LCodeGen::EmitTypeofIs(Label* true_label,
4788 Label* false_label,
4789 Register input,
4790 Handle<String> type_name) {
4791 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004792 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004793 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004794 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004796 final_branch_condition = equal;
4797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004798 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004799 __ JumpIfSmi(input, false_label);
4800 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
4801 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004802 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4803 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004804 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004805
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004806 } else if (type_name->Equals(heap()->boolean_symbol())) {
4807 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004808 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004809 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004810 final_branch_condition = equal;
4811
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004812 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
4813 __ cmp(input, factory()->null_value());
4814 final_branch_condition = equal;
4815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004816 } else if (type_name->Equals(heap()->undefined_symbol())) {
4817 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004818 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004819 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004820 // Check for undetectable objects => true.
4821 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
4822 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4823 1 << Map::kIsUndetectable);
4824 final_branch_condition = not_zero;
4825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004827 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004828 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004829 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
4830 __ j(equal, true_label);
4831 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
4832 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004834 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004835 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004836 if (!FLAG_harmony_typeof) {
4837 __ cmp(input, factory()->null_value());
4838 __ j(equal, true_label);
4839 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004840 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004841 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004842 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4843 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004844 // Check for undetectable objects => false.
4845 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4846 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004847 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004848
4849 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004850 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004851 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004852 return final_branch_condition;
4853}
4854
4855
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004856void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4857 Register temp = ToRegister(instr->TempAt(0));
4858 int true_block = chunk_->LookupDestination(instr->true_block_id());
4859 int false_block = chunk_->LookupDestination(instr->false_block_id());
4860
4861 EmitIsConstructCall(temp);
4862 EmitBranch(true_block, false_block, equal);
4863}
4864
4865
4866void LCodeGen::EmitIsConstructCall(Register temp) {
4867 // Get the frame pointer for the calling frame.
4868 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4869
4870 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004871 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004872 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4873 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004874 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004875 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
4876
4877 // Check the marker in the calling frame.
4878 __ bind(&check_frame_marker);
4879 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4880 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
4881}
4882
4883
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004884void LCodeGen::EnsureSpaceForLazyDeopt() {
4885 // Ensure that we have enough space after the previous lazy-bailout
4886 // instruction for patching the code here.
4887 int current_pc = masm()->pc_offset();
4888 int patch_size = Deoptimizer::patch_size();
4889 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
4890 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004891 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004892 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004893 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004894}
4895
4896
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004897void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004898 EnsureSpaceForLazyDeopt();
4899 ASSERT(instr->HasEnvironment());
4900 LEnvironment* env = instr->environment();
4901 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4902 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004903}
4904
4905
4906void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4907 DeoptimizeIf(no_condition, instr->environment());
4908}
4909
4910
4911void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
4912 LOperand* obj = instr->object();
4913 LOperand* key = instr->key();
4914 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004915 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00004916 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004917 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004918 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004919 // Create safepoint generator that will also ensure enough space in the
4920 // reloc info for patching in deoptimization (since this is invoking a
4921 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004922 SafepointGenerator safepoint_generator(
4923 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004924 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004925 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004926}
4927
4928
ager@chromium.org04921a82011-06-27 13:21:41 +00004929void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004930 PushSafepointRegistersScope scope(this);
4931 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4932 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
4933 RecordSafepointWithLazyDeopt(
4934 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
4935 ASSERT(instr->HasEnvironment());
4936 LEnvironment* env = instr->environment();
4937 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004938}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004939
ager@chromium.org04921a82011-06-27 13:21:41 +00004940
4941void LCodeGen::DoStackCheck(LStackCheck* instr) {
4942 class DeferredStackCheck: public LDeferredCode {
4943 public:
4944 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
4945 : LDeferredCode(codegen), instr_(instr) { }
4946 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004947 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00004948 private:
4949 LStackCheck* instr_;
4950 };
4951
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004952 ASSERT(instr->HasEnvironment());
4953 LEnvironment* env = instr->environment();
4954 // There is no LLazyBailout instruction for stack-checks. We have to
4955 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00004956 if (instr->hydrogen()->is_function_entry()) {
4957 // Perform stack overflow check.
4958 Label done;
4959 ExternalReference stack_limit =
4960 ExternalReference::address_of_stack_limit(isolate());
4961 __ cmp(esp, Operand::StaticVariable(stack_limit));
4962 __ j(above_equal, &done, Label::kNear);
4963
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004964 ASSERT(instr->context()->IsRegister());
4965 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00004966 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004967 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004968 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00004969 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004970 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4971 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004972 } else {
4973 ASSERT(instr->hydrogen()->is_backwards_branch());
4974 // Perform stack overflow check if this goto needs it before jumping.
4975 DeferredStackCheck* deferred_stack_check =
4976 new DeferredStackCheck(this, instr);
4977 ExternalReference stack_limit =
4978 ExternalReference::address_of_stack_limit(isolate());
4979 __ cmp(esp, Operand::StaticVariable(stack_limit));
4980 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004981 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00004982 __ bind(instr->done_label());
4983 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004984 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4985 // Don't record a deoptimization index for the safepoint here.
4986 // This will be done explicitly when emitting call and the safepoint in
4987 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00004988 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004989}
4990
4991
4992void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
4993 // This is a pseudo-instruction that ensures that the environment here is
4994 // properly registered for deoptimization and records the assembler's PC
4995 // offset.
4996 LEnvironment* environment = instr->environment();
4997 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4998 instr->SpilledDoubleRegisterArray());
4999
5000 // If the environment were already registered, we would have no way of
5001 // backpatching it with the spill slot operands.
5002 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005003 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005004 ASSERT(osr_pc_offset_ == -1);
5005 osr_pc_offset_ = masm()->pc_offset();
5006}
5007
5008
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005009void LCodeGen::DoIn(LIn* instr) {
5010 LOperand* obj = instr->object();
5011 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005012 EmitPushTaggedOperand(key);
5013 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005014 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005015 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005016 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005017 SafepointGenerator safepoint_generator(
5018 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005019 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005020}
5021
5022
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005023void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5024 __ cmp(eax, isolate()->factory()->undefined_value());
5025 DeoptimizeIf(equal, instr->environment());
5026
5027 __ cmp(eax, isolate()->factory()->null_value());
5028 DeoptimizeIf(equal, instr->environment());
5029
5030 __ test(eax, Immediate(kSmiTagMask));
5031 DeoptimizeIf(zero, instr->environment());
5032
5033 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5034 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5035 DeoptimizeIf(below_equal, instr->environment());
5036
5037 Label use_cache, call_runtime;
5038 __ CheckEnumCache(&call_runtime);
5039
5040 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5041 __ jmp(&use_cache, Label::kNear);
5042
5043 // Get the set of properties to enumerate.
5044 __ bind(&call_runtime);
5045 __ push(eax);
5046 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5047
5048 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5049 isolate()->factory()->meta_map());
5050 DeoptimizeIf(not_equal, instr->environment());
5051 __ bind(&use_cache);
5052}
5053
5054
5055void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5056 Register map = ToRegister(instr->map());
5057 Register result = ToRegister(instr->result());
5058 __ LoadInstanceDescriptors(map, result);
5059 __ mov(result,
5060 FieldOperand(result, DescriptorArray::kEnumerationIndexOffset));
5061 __ mov(result,
5062 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
5063 __ test(result, result);
5064 DeoptimizeIf(equal, instr->environment());
5065}
5066
5067
5068void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5069 Register object = ToRegister(instr->value());
5070 __ cmp(ToRegister(instr->map()),
5071 FieldOperand(object, HeapObject::kMapOffset));
5072 DeoptimizeIf(not_equal, instr->environment());
5073}
5074
5075
5076void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5077 Register object = ToRegister(instr->object());
5078 Register index = ToRegister(instr->index());
5079
5080 Label out_of_object, done;
5081 __ cmp(index, Immediate(0));
5082 __ j(less, &out_of_object);
5083 __ mov(object, FieldOperand(object,
5084 index,
5085 times_half_pointer_size,
5086 JSObject::kHeaderSize));
5087 __ jmp(&done, Label::kNear);
5088
5089 __ bind(&out_of_object);
5090 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5091 __ neg(index);
5092 // Index is now equal to out of object property index plus 1.
5093 __ mov(object, FieldOperand(object,
5094 index,
5095 times_half_pointer_size,
5096 FixedArray::kHeaderSize - kPointerSize));
5097 __ bind(&done);
5098}
5099
5100
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005101#undef __
5102
5103} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005104
5105#endif // V8_TARGET_ARCH_IA32