blob: 33efdd89e1dce0c9fcea673f3b5ff3ed8feb61ac [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
mmassi@chromium.org7028c052012-06-13 11:51:58 +000082 dynamic_frame_alignment_ = (chunk()->num_double_slots() > 2 &&
83 !chunk()->graph()->is_recursive()) ||
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000084 !info()->osr_ast_id().IsNone();
mmassi@chromium.org7028c052012-06-13 11:51:58 +000085
kasperl@chromium.orga5551262010-12-07 12:49:48 +000086 return GeneratePrologue() &&
87 GenerateBody() &&
88 GenerateDeferredCode() &&
89 GenerateSafepointTable();
90}
91
92
93void LCodeGen::FinishCode(Handle<Code> code) {
94 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000095 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000096 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000098 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000099}
100
101
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000102void LCodeGen::Abort(const char* reason) {
103 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000104 status_ = ABORTED;
105}
106
107
108void LCodeGen::Comment(const char* format, ...) {
109 if (!FLAG_code_comments) return;
110 char buffer[4 * KB];
111 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
112 va_list arguments;
113 va_start(arguments, format);
114 builder.AddFormattedList(format, arguments);
115 va_end(arguments);
116
117 // Copy the string before recording it in the assembler to avoid
118 // issues when the stack allocated buffer goes out of scope.
119 size_t length = builder.position();
120 Vector<char> copy = Vector<char>::New(length + 1);
121 memcpy(copy.start(), builder.Finalize(), copy.length());
122 masm()->RecordComment(copy.start());
123}
124
125
126bool LCodeGen::GeneratePrologue() {
127 ASSERT(is_generating());
128
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000129 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
130
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000131#ifdef DEBUG
132 if (strlen(FLAG_stop_at) > 0 &&
133 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
134 __ int3();
135 }
136#endif
137
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000138 // Strict mode functions and builtins need to replace the receiver
139 // with undefined when called as functions (without an explicit
140 // receiver object). ecx is zero for method calls and non-zero for
141 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000142 if (!info_->is_classic_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000143 Label ok;
144 __ test(ecx, Operand(ecx));
145 __ j(zero, &ok, Label::kNear);
146 // +1 for return address.
147 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
148 __ mov(Operand(esp, receiver_offset),
149 Immediate(isolate()->factory()->undefined_value()));
150 __ bind(&ok);
151 }
152
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000153
154 if (dynamic_frame_alignment_) {
155 // Move state of dynamic frame alignment into edx.
156 __ mov(edx, Immediate(kNoAlignmentPadding));
157
158 Label do_not_pad, align_loop;
159 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
160 // Align esp + 4 to a multiple of 2 * kPointerSize.
161 __ test(esp, Immediate(kPointerSize));
162 __ j(not_zero, &do_not_pad, Label::kNear);
163 __ push(Immediate(0));
164 __ mov(ebx, esp);
165 __ mov(edx, Immediate(kAlignmentPaddingPushed));
166 // Copy arguments, receiver, and return address.
167 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
168
169 __ bind(&align_loop);
170 __ mov(eax, Operand(ebx, 1 * kPointerSize));
171 __ mov(Operand(ebx, 0), eax);
172 __ add(Operand(ebx), Immediate(kPointerSize));
173 __ dec(ecx);
174 __ j(not_zero, &align_loop, Label::kNear);
175 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
176 __ bind(&do_not_pad);
177 }
178
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000179 __ push(ebp); // Caller's frame pointer.
180 __ mov(ebp, esp);
181 __ push(esi); // Callee's context.
182 __ push(edi); // Callee's JS function.
183
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000184 if (dynamic_frame_alignment_ && FLAG_debug_code) {
185 __ test(esp, Immediate(kPointerSize));
186 __ Assert(zero, "frame is expected to be aligned");
187 }
188
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000189 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000190 int slots = GetStackSlotCount();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000191 ASSERT_GE(slots, 1);
192 if (slots == 1) {
193 if (dynamic_frame_alignment_) {
194 __ push(edx);
195 } else {
196 __ push(Immediate(kNoAlignmentPadding));
197 }
198 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000199 if (FLAG_debug_code) {
200 __ mov(Operand(eax), Immediate(slots));
201 Label loop;
202 __ bind(&loop);
203 __ push(Immediate(kSlotsZapValue));
204 __ dec(eax);
205 __ j(not_zero, &loop);
206 } else {
207 __ sub(Operand(esp), Immediate(slots * kPointerSize));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000208 #ifdef _MSC_VER
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000209 // On windows, you may not access the stack more than one page below
210 // the most recently mapped page. To make the allocated area randomly
211 // accessible, we write to each page in turn (the value is irrelevant).
212 const int kPageSize = 4 * KB;
213 for (int offset = slots * kPointerSize - kPageSize;
214 offset > 0;
215 offset -= kPageSize) {
216 __ mov(Operand(esp, offset), eax);
217 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000218 #endif
219 }
220
221 // Store dynamic frame alignment state in the first local.
222 if (dynamic_frame_alignment_) {
223 __ mov(Operand(ebp,
224 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
225 edx);
226 } else {
227 __ mov(Operand(ebp,
228 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
229 Immediate(kNoAlignmentPadding));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000230 }
231 }
232
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000233 // Possibly allocate a local context.
234 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
235 if (heap_slots > 0) {
236 Comment(";;; Allocate local context");
237 // Argument to NewContext is the function, which is still in edi.
238 __ push(edi);
239 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
240 FastNewContextStub stub(heap_slots);
241 __ CallStub(&stub);
242 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000243 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000244 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000245 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000246 // Context is returned in both eax and esi. It replaces the context
247 // passed to us. It's saved in the stack and kept live in esi.
248 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
249
250 // Copy parameters into context if necessary.
251 int num_parameters = scope()->num_parameters();
252 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000253 Variable* var = scope()->parameter(i);
254 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000255 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
256 (num_parameters - 1 - i) * kPointerSize;
257 // Load parameter from stack.
258 __ mov(eax, Operand(ebp, parameter_offset));
259 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000260 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000261 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000262 // Update the write barrier. This clobbers eax and ebx.
263 __ RecordWriteContextSlot(esi,
264 context_offset,
265 eax,
266 ebx,
267 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000268 }
269 }
270 Comment(";;; End allocate local context");
271 }
272
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000273 // Trace the call.
274 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000275 // We have not executed any compiled code yet, so esi still holds the
276 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000277 __ CallRuntime(Runtime::kTraceEnter, 0);
278 }
279 return !is_aborted();
280}
281
282
283bool LCodeGen::GenerateBody() {
284 ASSERT(is_generating());
285 bool emit_instructions = true;
286 for (current_instruction_ = 0;
287 !is_aborted() && current_instruction_ < instructions_->length();
288 current_instruction_++) {
289 LInstruction* instr = instructions_->at(current_instruction_);
290 if (instr->IsLabel()) {
291 LLabel* label = LLabel::cast(instr);
292 emit_instructions = !label->HasReplacement();
293 }
294
295 if (emit_instructions) {
296 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
297 instr->CompileToNative(this);
298 }
299 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000300 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000301 return !is_aborted();
302}
303
304
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000305bool LCodeGen::GenerateDeferredCode() {
306 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000307 if (deferred_.length() > 0) {
308 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
309 LDeferredCode* code = deferred_[i];
310 __ bind(code->entry());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000311 Comment(";;; Deferred code @%d: %s.",
312 code->instruction_index(),
313 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000314 code->Generate();
315 __ jmp(code->exit());
316 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317 }
318
319 // Deferred code is the last part of the instruction sequence. Mark
320 // the generated code as done unless we bailed out.
321 if (!is_aborted()) status_ = DONE;
322 return !is_aborted();
323}
324
325
326bool LCodeGen::GenerateSafepointTable() {
327 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000328 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 return !is_aborted();
330}
331
332
333Register LCodeGen::ToRegister(int index) const {
334 return Register::FromAllocationIndex(index);
335}
336
337
338XMMRegister LCodeGen::ToDoubleRegister(int index) const {
339 return XMMRegister::FromAllocationIndex(index);
340}
341
342
343Register LCodeGen::ToRegister(LOperand* op) const {
344 ASSERT(op->IsRegister());
345 return ToRegister(op->index());
346}
347
348
349XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
350 ASSERT(op->IsDoubleRegister());
351 return ToDoubleRegister(op->index());
352}
353
354
355int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000356 HConstant* constant = chunk_->LookupConstant(op);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000357 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000358 ASSERT(constant->HasInteger32Value());
359 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000360}
361
362
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000363Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000364 HConstant* constant = chunk_->LookupConstant(op);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000365 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000366 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000367}
368
369
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000370double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000371 HConstant* constant = chunk_->LookupConstant(op);
372 ASSERT(constant->HasDoubleValue());
373 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000374}
375
376
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000377bool LCodeGen::IsInteger32(LConstantOperand* op) const {
378 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000379}
380
381
382Operand LCodeGen::ToOperand(LOperand* op) const {
383 if (op->IsRegister()) return Operand(ToRegister(op));
384 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
385 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
386 int index = op->index();
387 if (index >= 0) {
388 // Local or spill slot. Skip the frame pointer, function, and
389 // context in the fixed part of the frame.
390 return Operand(ebp, -(index + 3) * kPointerSize);
391 } else {
392 // Incoming parameter. Skip the return address.
393 return Operand(ebp, -(index - 1) * kPointerSize);
394 }
395}
396
397
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000398Operand LCodeGen::HighOperand(LOperand* op) {
399 ASSERT(op->IsDoubleStackSlot());
400 int index = op->index();
401 int offset = (index >= 0) ? index + 3 : index - 1;
402 return Operand(ebp, -offset * kPointerSize);
403}
404
405
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000406void LCodeGen::WriteTranslation(LEnvironment* environment,
407 Translation* translation) {
408 if (environment == NULL) return;
409
410 // The translation includes one command per value in the environment.
411 int translation_size = environment->values()->length();
412 // The output frame height does not include the parameters.
413 int height = translation_size - environment->parameter_count();
414
415 WriteTranslation(environment->outer(), translation);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000416 int closure_id = *info()->closure() != *environment->closure()
417 ? DefineDeoptimizationLiteral(environment->closure())
418 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000419 switch (environment->frame_type()) {
420 case JS_FUNCTION:
421 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
422 break;
423 case JS_CONSTRUCT:
424 translation->BeginConstructStubFrame(closure_id, translation_size);
425 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000426 case JS_GETTER:
427 ASSERT(translation_size == 1);
428 ASSERT(height == 0);
429 translation->BeginGetterStubFrame(closure_id);
430 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000431 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000432 ASSERT(translation_size == 2);
433 ASSERT(height == 0);
434 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000435 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000436 case ARGUMENTS_ADAPTOR:
437 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
438 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000439 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000440 for (int i = 0; i < translation_size; ++i) {
441 LOperand* value = environment->values()->at(i);
442 // spilled_registers_ and spilled_double_registers_ are either
443 // both NULL or both set.
444 if (environment->spilled_registers() != NULL && value != NULL) {
445 if (value->IsRegister() &&
446 environment->spilled_registers()[value->index()] != NULL) {
447 translation->MarkDuplicate();
448 AddToTranslation(translation,
449 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000450 environment->HasTaggedValueAt(i),
451 environment->HasUint32ValueAt(i));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000452 } else if (
453 value->IsDoubleRegister() &&
454 environment->spilled_double_registers()[value->index()] != NULL) {
455 translation->MarkDuplicate();
456 AddToTranslation(
457 translation,
458 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000459 false,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000460 false);
461 }
462 }
463
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000464 AddToTranslation(translation,
465 value,
466 environment->HasTaggedValueAt(i),
467 environment->HasUint32ValueAt(i));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000468 }
469}
470
471
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472void LCodeGen::AddToTranslation(Translation* translation,
473 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000474 bool is_tagged,
475 bool is_uint32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000476 if (op == NULL) {
477 // TODO(twuerthinger): Introduce marker operands to indicate that this value
478 // is not present and must be reconstructed from the deoptimizer. Currently
479 // this is only used for the arguments object.
480 translation->StoreArgumentsObject();
481 } else if (op->IsStackSlot()) {
482 if (is_tagged) {
483 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000484 } else if (is_uint32) {
485 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000486 } else {
487 translation->StoreInt32StackSlot(op->index());
488 }
489 } else if (op->IsDoubleStackSlot()) {
490 translation->StoreDoubleStackSlot(op->index());
491 } else if (op->IsArgument()) {
492 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000493 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000494 translation->StoreStackSlot(src_index);
495 } else if (op->IsRegister()) {
496 Register reg = ToRegister(op);
497 if (is_tagged) {
498 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000499 } else if (is_uint32) {
500 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000501 } else {
502 translation->StoreInt32Register(reg);
503 }
504 } else if (op->IsDoubleRegister()) {
505 XMMRegister reg = ToDoubleRegister(op);
506 translation->StoreDoubleRegister(reg);
507 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000508 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
509 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000510 translation->StoreLiteral(src_index);
511 } else {
512 UNREACHABLE();
513 }
514}
515
516
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000517void LCodeGen::CallCodeGeneric(Handle<Code> code,
518 RelocInfo::Mode mode,
519 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000520 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000521 ASSERT(instr != NULL);
522 LPointerMap* pointers = instr->pointer_map();
523 RecordPosition(pointers->position());
524 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000525 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000526
527 // Signal that we don't inline smi code before these stubs in the
528 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000529 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000530 code->kind() == Code::COMPARE_IC) {
531 __ nop();
532 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533}
534
535
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000536void LCodeGen::CallCode(Handle<Code> code,
537 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000538 LInstruction* instr) {
539 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000540}
541
542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000544 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000545 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000546 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000547 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000548 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 RecordPosition(pointers->position());
550
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000551 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000552
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000553 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000554}
555
556
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000557void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
558 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000559 LInstruction* instr,
560 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000561 if (context->IsRegister()) {
562 if (!ToRegister(context).is(esi)) {
563 __ mov(esi, ToRegister(context));
564 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000565 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000566 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000567 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000568 HConstant* constant =
569 chunk_->LookupConstant(LConstantOperand::cast(context));
570 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000571 } else {
572 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000573 }
574
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000575 __ CallRuntimeSaveDoubles(id);
576 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000577 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000578}
579
580
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000581void LCodeGen::RegisterEnvironmentForDeoptimization(
582 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000583 if (!environment->HasBeenRegistered()) {
584 // Physical stack frame layout:
585 // -x ............. -4 0 ..................................... y
586 // [incoming arguments] [spill slots] [pushed outgoing arguments]
587
588 // Layout of the environment:
589 // 0 ..................................................... size-1
590 // [parameters] [locals] [expression stack including arguments]
591
592 // Layout of the translation:
593 // 0 ........................................................ size - 1 + 4
594 // [expression stack including arguments] [locals] [4 words] [parameters]
595 // |>------------ translation_size ------------<|
596
597 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000598 int jsframe_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
600 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000601 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000602 ++jsframe_count;
603 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000604 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000605 Translation translation(&translations_, frame_count, jsframe_count,
606 zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000607 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000608 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000609 int pc_offset = masm()->pc_offset();
610 environment->Register(deoptimization_index,
611 translation.index(),
612 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000613 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000614 }
615}
616
617
618void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000619 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000620 ASSERT(environment->HasBeenRegistered());
621 int id = environment->deoptimization_index();
622 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000623 if (entry == NULL) {
624 Abort("bailout was not prepared");
625 return;
626 }
627
628 if (FLAG_deopt_every_n_times != 0) {
629 Handle<SharedFunctionInfo> shared(info_->shared_info());
630 Label no_deopt;
631 __ pushfd();
632 __ push(eax);
633 __ push(ebx);
634 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000635 __ mov(eax,
636 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000637 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000638 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000639 if (FLAG_trap_on_deopt) __ int3();
640 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000641 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
642 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000643 __ pop(ebx);
644 __ pop(eax);
645 __ popfd();
646 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
647
648 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000649 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
650 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000651 __ pop(ebx);
652 __ pop(eax);
653 __ popfd();
654 }
655
656 if (cc == no_condition) {
657 if (FLAG_trap_on_deopt) __ int3();
658 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
659 } else {
660 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000661 Label done;
662 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000663 __ int3();
664 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
665 __ bind(&done);
666 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000667 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000668 }
669 }
670}
671
672
673void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
674 int length = deoptimizations_.length();
675 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000676 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000679 Handle<ByteArray> translations = translations_.CreateByteArray();
680 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000681 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
682
683 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000684 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 for (int i = 0; i < deoptimization_literals_.length(); i++) {
686 literals->set(i, *deoptimization_literals_[i]);
687 }
688 data->SetLiteralArray(*literals);
689
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000690 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000691 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
692
693 // Populate the deoptimization entries.
694 for (int i = 0; i < length; i++) {
695 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000696 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000697 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
698 data->SetArgumentsStackHeight(i,
699 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000700 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701 }
702 code->set_deoptimization_data(*data);
703}
704
705
706int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
707 int result = deoptimization_literals_.length();
708 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
709 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
710 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000711 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712 return result;
713}
714
715
716void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
717 ASSERT(deoptimization_literals_.length() == 0);
718
719 const ZoneList<Handle<JSFunction> >* inlined_closures =
720 chunk()->inlined_closures();
721
722 for (int i = 0, length = inlined_closures->length();
723 i < length;
724 i++) {
725 DefineDeoptimizationLiteral(inlined_closures->at(i));
726 }
727
728 inlined_function_count_ = deoptimization_literals_.length();
729}
730
731
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000732void LCodeGen::RecordSafepointWithLazyDeopt(
733 LInstruction* instr, SafepointMode safepoint_mode) {
734 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
735 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
736 } else {
737 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
738 RecordSafepointWithRegisters(
739 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
740 }
741}
742
743
ager@chromium.org378b34e2011-01-28 08:04:38 +0000744void LCodeGen::RecordSafepoint(
745 LPointerMap* pointers,
746 Safepoint::Kind kind,
747 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000748 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000749 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000750 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000751 Safepoint safepoint =
752 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000753 for (int i = 0; i < operands->length(); i++) {
754 LOperand* pointer = operands->at(i);
755 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000756 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000757 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000758 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000759 }
760 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000761}
762
763
764void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000765 Safepoint::DeoptMode mode) {
766 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000767}
768
769
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000770void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000771 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000772 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000773}
774
775
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
777 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000778 Safepoint::DeoptMode mode) {
779 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000780}
781
782
783void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000784 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000785 masm()->positions_recorder()->RecordPosition(position);
786}
787
788
789void LCodeGen::DoLabel(LLabel* label) {
790 if (label->is_loop_header()) {
791 Comment(";;; B%d - LOOP entry", label->block_id());
792 } else {
793 Comment(";;; B%d", label->block_id());
794 }
795 __ bind(label->label());
796 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000797 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000798}
799
800
801void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000802 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000803}
804
805
806void LCodeGen::DoGap(LGap* gap) {
807 for (int i = LGap::FIRST_INNER_POSITION;
808 i <= LGap::LAST_INNER_POSITION;
809 i++) {
810 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
811 LParallelMove* move = gap->GetParallelMove(inner_pos);
812 if (move != NULL) DoParallelMove(move);
813 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000814}
815
816
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000817void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
818 DoGap(instr);
819}
820
821
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000822void LCodeGen::DoParameter(LParameter* instr) {
823 // Nothing to do.
824}
825
826
827void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000828 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 ASSERT(ToRegister(instr->result()).is(eax));
830 switch (instr->hydrogen()->major_key()) {
831 case CodeStub::RegExpConstructResult: {
832 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000833 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000834 break;
835 }
836 case CodeStub::RegExpExec: {
837 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000838 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000839 break;
840 }
841 case CodeStub::SubString: {
842 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000843 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000844 break;
845 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000846 case CodeStub::NumberToString: {
847 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000848 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000849 break;
850 }
851 case CodeStub::StringAdd: {
852 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000853 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000854 break;
855 }
856 case CodeStub::StringCompare: {
857 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000858 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000859 break;
860 }
861 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000862 TranscendentalCacheStub stub(instr->transcendental_type(),
863 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000864 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000865 break;
866 }
867 default:
868 UNREACHABLE();
869 }
870}
871
872
873void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
874 // Nothing to do.
875}
876
877
878void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000879 if (instr->hydrogen()->HasPowerOf2Divisor()) {
880 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000881
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000882 int32_t divisor =
883 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000884
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000885 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000886
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000887 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000888 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000889 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000890 __ neg(dividend);
891 __ and_(dividend, divisor - 1);
892 __ neg(dividend);
893 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000894 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000895 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000896 } else {
897 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000898 }
899 __ bind(&positive_dividend);
900 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000901 __ bind(&done);
902 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000903 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000904 Register left_reg = ToRegister(instr->InputAt(0));
905 Register right_reg = ToRegister(instr->InputAt(1));
906 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000907
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000908 ASSERT(left_reg.is(eax));
909 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000910 ASSERT(!right_reg.is(eax));
911 ASSERT(!right_reg.is(edx));
912
913 // Check for x % 0.
914 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000915 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000916 DeoptimizeIf(zero, instr->environment());
917 }
918
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000919 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000920 __ j(zero, &remainder_eq_dividend, Label::kNear);
921 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000922
923 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000924 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000925 // The sign of the divisor doesn't matter.
926 __ neg(right_reg);
927
928 __ bind(&both_positive);
929 // If the dividend is smaller than the nonnegative
930 // divisor, the dividend is the result.
931 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000932 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000933
934 // Check if the divisor is a PowerOfTwo integer.
935 Register scratch = ToRegister(instr->TempAt(0));
936 __ mov(scratch, right_reg);
937 __ sub(Operand(scratch), Immediate(1));
938 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000939 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000940 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000941 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000942
943 __ bind(&do_subtraction);
944 const int kUnfolds = 3;
945 // Try a few subtractions of the dividend.
946 __ mov(scratch, left_reg);
947 for (int i = 0; i < kUnfolds; i++) {
948 // Reduce the dividend by the divisor.
949 __ sub(left_reg, Operand(right_reg));
950 // Check if the dividend is less than the divisor.
951 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000952 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000953 }
954 __ mov(left_reg, scratch);
955
956 // Slow case, using idiv instruction.
957 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000958 // Sign extend to edx.
959 __ cdq();
960
961 // Check for (0 % -x) that will produce negative zero.
962 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000963 Label positive_left;
964 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000965 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000966 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000967 __ idiv(right_reg);
968
969 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000970 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000971 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000972
973 DeoptimizeIf(no_condition, instr->environment());
974 __ bind(&positive_left);
975 __ idiv(right_reg);
976 __ bind(&done);
977 } else {
978 __ idiv(right_reg);
979 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000980 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000981
982 __ bind(&remainder_eq_dividend);
983 __ mov(result_reg, left_reg);
984
985 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000986 }
987}
988
989
990void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000991 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000992 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000993 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
994 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
995 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996
997 Register left_reg = eax;
998
999 // Check for x / 0.
1000 Register right_reg = ToRegister(right);
1001 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1002 __ test(right_reg, ToOperand(right));
1003 DeoptimizeIf(zero, instr->environment());
1004 }
1005
1006 // Check for (0 / -x) that will produce negative zero.
1007 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001008 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001009 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001010 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001011 __ test(right_reg, ToOperand(right));
1012 DeoptimizeIf(sign, instr->environment());
1013 __ bind(&left_not_zero);
1014 }
1015
1016 // Check for (-kMinInt / -1).
1017 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001018 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001020 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001021 __ cmp(right_reg, -1);
1022 DeoptimizeIf(zero, instr->environment());
1023 __ bind(&left_not_min_int);
1024 }
1025
1026 // Sign extend to edx.
1027 __ cdq();
1028 __ idiv(right_reg);
1029
1030 // Deoptimize if remainder is not 0.
1031 __ test(edx, Operand(edx));
1032 DeoptimizeIf(not_zero, instr->environment());
1033}
1034
1035
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001036void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1037 ASSERT(instr->InputAt(1)->IsConstantOperand());
1038
1039 Register dividend = ToRegister(instr->InputAt(0));
1040 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1)));
1041 Register result = ToRegister(instr->result());
1042
1043 switch (divisor) {
1044 case 0:
1045 DeoptimizeIf(no_condition, instr->environment());
1046 return;
1047
1048 case 1:
1049 __ Move(result, dividend);
1050 return;
1051
1052 case -1:
1053 __ Move(result, dividend);
1054 __ neg(result);
1055 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1056 DeoptimizeIf(zero, instr->environment());
1057 }
1058 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1059 DeoptimizeIf(overflow, instr->environment());
1060 }
1061 return;
1062 }
1063
1064 uint32_t divisor_abs = abs(divisor);
1065 if (IsPowerOf2(divisor_abs)) {
1066 int32_t power = WhichPowerOf2(divisor_abs);
1067 if (divisor < 0) {
1068 // Input[dividend] is clobbered.
1069 // The sequence is tedious because neg(dividend) might overflow.
1070 __ mov(result, dividend);
1071 __ sar(dividend, 31);
1072 __ neg(result);
1073 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1074 DeoptimizeIf(zero, instr->environment());
1075 }
1076 __ shl(dividend, 32 - power);
1077 __ sar(result, power);
1078 __ not_(dividend);
1079 // Clear result.sign if dividend.sign is set.
1080 __ and_(result, dividend);
1081 } else {
1082 __ Move(result, dividend);
1083 __ sar(result, power);
1084 }
1085 } else {
1086 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
1087 ASSERT(ToRegister(instr->result()).is(edx));
1088 Register scratch = ToRegister(instr->TempAt(0));
1089
1090 // Find b which: 2^b < divisor_abs < 2^(b+1).
1091 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1092 unsigned shift = 32 + b; // Precision +1bit (effectively).
1093 double multiplier_f =
1094 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1095 int64_t multiplier;
1096 if (multiplier_f - floor(multiplier_f) < 0.5) {
1097 multiplier = static_cast<int64_t>(floor(multiplier_f));
1098 } else {
1099 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1100 }
1101 // The multiplier is a uint32.
1102 ASSERT(multiplier > 0 &&
1103 multiplier < (static_cast<int64_t>(1) << 32));
1104 __ mov(scratch, dividend);
1105 if (divisor < 0 &&
1106 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1107 __ test(dividend, dividend);
1108 DeoptimizeIf(zero, instr->environment());
1109 }
1110 __ mov(edx, static_cast<int32_t>(multiplier));
1111 __ imul(edx);
1112 if (static_cast<int32_t>(multiplier) < 0) {
1113 __ add(edx, scratch);
1114 }
1115 Register reg_lo = eax;
1116 Register reg_byte_scratch = scratch;
1117 if (!reg_byte_scratch.is_byte_register()) {
1118 __ xchg(reg_lo, reg_byte_scratch);
1119 reg_lo = scratch;
1120 reg_byte_scratch = eax;
1121 }
1122 if (divisor < 0) {
1123 __ xor_(reg_byte_scratch, reg_byte_scratch);
1124 __ cmp(reg_lo, 0x40000000);
1125 __ setcc(above, reg_byte_scratch);
1126 __ neg(edx);
1127 __ sub(edx, reg_byte_scratch);
1128 } else {
1129 __ xor_(reg_byte_scratch, reg_byte_scratch);
1130 __ cmp(reg_lo, 0xC0000000);
1131 __ setcc(above_equal, reg_byte_scratch);
1132 __ add(edx, reg_byte_scratch);
1133 }
1134 __ sar(edx, shift - 32);
1135 }
1136}
1137
1138
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001139void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001140 Register left = ToRegister(instr->InputAt(0));
1141 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001142
1143 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001144 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001145 }
1146
1147 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001148 // Try strength reductions on the multiplication.
1149 // All replacement instructions are at most as long as the imul
1150 // and have better latency.
1151 int constant = ToInteger32(LConstantOperand::cast(right));
1152 if (constant == -1) {
1153 __ neg(left);
1154 } else if (constant == 0) {
1155 __ xor_(left, Operand(left));
1156 } else if (constant == 2) {
1157 __ add(left, Operand(left));
1158 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1159 // If we know that the multiplication can't overflow, it's safe to
1160 // use instructions that don't set the overflow flag for the
1161 // multiplication.
1162 switch (constant) {
1163 case 1:
1164 // Do nothing.
1165 break;
1166 case 3:
1167 __ lea(left, Operand(left, left, times_2, 0));
1168 break;
1169 case 4:
1170 __ shl(left, 2);
1171 break;
1172 case 5:
1173 __ lea(left, Operand(left, left, times_4, 0));
1174 break;
1175 case 8:
1176 __ shl(left, 3);
1177 break;
1178 case 9:
1179 __ lea(left, Operand(left, left, times_8, 0));
1180 break;
1181 case 16:
1182 __ shl(left, 4);
1183 break;
1184 default:
1185 __ imul(left, left, constant);
1186 break;
1187 }
1188 } else {
1189 __ imul(left, left, constant);
1190 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001191 } else {
1192 __ imul(left, ToOperand(right));
1193 }
1194
1195 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1196 DeoptimizeIf(overflow, instr->environment());
1197 }
1198
1199 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1200 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001201 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001202 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001203 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001204 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001205 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001206 DeoptimizeIf(no_condition, instr->environment());
1207 }
1208 } else {
1209 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001210 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001211 DeoptimizeIf(sign, instr->environment());
1212 }
1213 __ bind(&done);
1214 }
1215}
1216
1217
1218void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001219 LOperand* left = instr->InputAt(0);
1220 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001221 ASSERT(left->Equals(instr->result()));
1222 ASSERT(left->IsRegister());
1223
1224 if (right->IsConstantOperand()) {
1225 int right_operand = ToInteger32(LConstantOperand::cast(right));
1226 switch (instr->op()) {
1227 case Token::BIT_AND:
1228 __ and_(ToRegister(left), right_operand);
1229 break;
1230 case Token::BIT_OR:
1231 __ or_(ToRegister(left), right_operand);
1232 break;
1233 case Token::BIT_XOR:
1234 __ xor_(ToRegister(left), right_operand);
1235 break;
1236 default:
1237 UNREACHABLE();
1238 break;
1239 }
1240 } else {
1241 switch (instr->op()) {
1242 case Token::BIT_AND:
1243 __ and_(ToRegister(left), ToOperand(right));
1244 break;
1245 case Token::BIT_OR:
1246 __ or_(ToRegister(left), ToOperand(right));
1247 break;
1248 case Token::BIT_XOR:
1249 __ xor_(ToRegister(left), ToOperand(right));
1250 break;
1251 default:
1252 UNREACHABLE();
1253 break;
1254 }
1255 }
1256}
1257
1258
1259void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001260 LOperand* left = instr->InputAt(0);
1261 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001262 ASSERT(left->Equals(instr->result()));
1263 ASSERT(left->IsRegister());
1264 if (right->IsRegister()) {
1265 ASSERT(ToRegister(right).is(ecx));
1266
1267 switch (instr->op()) {
1268 case Token::SAR:
1269 __ sar_cl(ToRegister(left));
1270 break;
1271 case Token::SHR:
1272 __ shr_cl(ToRegister(left));
1273 if (instr->can_deopt()) {
1274 __ test(ToRegister(left), Immediate(0x80000000));
1275 DeoptimizeIf(not_zero, instr->environment());
1276 }
1277 break;
1278 case Token::SHL:
1279 __ shl_cl(ToRegister(left));
1280 break;
1281 default:
1282 UNREACHABLE();
1283 break;
1284 }
1285 } else {
1286 int value = ToInteger32(LConstantOperand::cast(right));
1287 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1288 switch (instr->op()) {
1289 case Token::SAR:
1290 if (shift_count != 0) {
1291 __ sar(ToRegister(left), shift_count);
1292 }
1293 break;
1294 case Token::SHR:
1295 if (shift_count == 0 && instr->can_deopt()) {
1296 __ test(ToRegister(left), Immediate(0x80000000));
1297 DeoptimizeIf(not_zero, instr->environment());
1298 } else {
1299 __ shr(ToRegister(left), shift_count);
1300 }
1301 break;
1302 case Token::SHL:
1303 if (shift_count != 0) {
1304 __ shl(ToRegister(left), shift_count);
1305 }
1306 break;
1307 default:
1308 UNREACHABLE();
1309 break;
1310 }
1311 }
1312}
1313
1314
1315void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001316 LOperand* left = instr->InputAt(0);
1317 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001318 ASSERT(left->Equals(instr->result()));
1319
1320 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001321 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001322 } else {
1323 __ sub(ToRegister(left), ToOperand(right));
1324 }
1325 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1326 DeoptimizeIf(overflow, instr->environment());
1327 }
1328}
1329
1330
1331void LCodeGen::DoConstantI(LConstantI* instr) {
1332 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001333 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001334}
1335
1336
1337void LCodeGen::DoConstantD(LConstantD* instr) {
1338 ASSERT(instr->result()->IsDoubleRegister());
1339 XMMRegister res = ToDoubleRegister(instr->result());
1340 double v = instr->value();
1341 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1342 // do so if the constant is -0.0.
1343 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001344 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001346 Register temp = ToRegister(instr->TempAt(0));
1347 uint64_t int_val = BitCast<uint64_t, double>(v);
1348 int32_t lower = static_cast<int32_t>(int_val);
1349 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001350 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001351 CpuFeatures::Scope scope(SSE4_1);
1352 if (lower != 0) {
1353 __ Set(temp, Immediate(lower));
1354 __ movd(res, Operand(temp));
1355 __ Set(temp, Immediate(upper));
1356 __ pinsrd(res, Operand(temp), 1);
1357 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001358 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001359 __ Set(temp, Immediate(upper));
1360 __ pinsrd(res, Operand(temp), 1);
1361 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001362 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001363 __ Set(temp, Immediate(upper));
1364 __ movd(res, Operand(temp));
1365 __ psllq(res, 32);
1366 if (lower != 0) {
1367 __ Set(temp, Immediate(lower));
1368 __ movd(xmm0, Operand(temp));
1369 __ por(res, xmm0);
1370 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001371 }
1372 }
1373}
1374
1375
1376void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 Register reg = ToRegister(instr->result());
1378 Handle<Object> handle = instr->value();
1379 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001380 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 } else {
1382 __ Set(reg, Immediate(handle));
1383 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001384}
1385
1386
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001387void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001389 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001390 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1391}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001392
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001393
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001394void LCodeGen::DoFixedArrayBaseLength(
1395 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001396 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001397 Register array = ToRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001398 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001399}
1400
1401
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001402void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1403 Register result = ToRegister(instr->result());
1404 Register map = ToRegister(instr->InputAt(0));
1405 __ EnumLength(result, map);
1406}
1407
1408
whesse@chromium.org7b260152011-06-20 15:33:18 +00001409void LCodeGen::DoElementsKind(LElementsKind* instr) {
1410 Register result = ToRegister(instr->result());
1411 Register input = ToRegister(instr->InputAt(0));
1412
1413 // Load map into |result|.
1414 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1415 // Load the map's "bit field 2" into |result|. We only need the first byte,
1416 // but the following masking takes care of that anyway.
1417 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1418 // Retrieve elements_kind from bit field 2.
1419 __ and_(result, Map::kElementsKindMask);
1420 __ shr(result, Map::kElementsKindShift);
1421}
1422
1423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001424void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001425 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001427 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001428 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001429
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001430 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001431 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001432 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001433
1434 // If the object is not a value type, return the object.
1435 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001436 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001437 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1438
1439 __ bind(&done);
1440}
1441
1442
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001443void LCodeGen::DoDateField(LDateField* instr) {
1444 Register object = ToRegister(instr->InputAt(0));
1445 Register result = ToRegister(instr->result());
1446 Register scratch = ToRegister(instr->TempAt(0));
1447 Smi* index = instr->index();
1448 Label runtime, done;
1449 ASSERT(object.is(result));
1450 ASSERT(object.is(eax));
1451
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001452 __ test(object, Immediate(kSmiTagMask));
1453 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001454 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001455 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001456
1457 if (index->value() == 0) {
1458 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1459 } else {
1460 if (index->value() < JSDate::kFirstUncachedField) {
1461 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1462 __ mov(scratch, Operand::StaticVariable(stamp));
1463 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1464 __ j(not_equal, &runtime, Label::kNear);
1465 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1466 kPointerSize * index->value()));
1467 __ jmp(&done);
1468 }
1469 __ bind(&runtime);
1470 __ PrepareCallCFunction(2, scratch);
1471 __ mov(Operand(esp, 0), object);
1472 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1473 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1474 __ bind(&done);
1475 }
1476}
1477
1478
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001480 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001481 ASSERT(input->Equals(instr->result()));
1482 __ not_(ToRegister(input));
1483}
1484
1485
1486void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001487 __ push(ToOperand(instr->value()));
1488 ASSERT(ToRegister(instr->context()).is(esi));
1489 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001490
1491 if (FLAG_debug_code) {
1492 Comment("Unreachable code.");
1493 __ int3();
1494 }
1495}
1496
1497
1498void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001499 LOperand* left = instr->InputAt(0);
1500 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001501 ASSERT(left->Equals(instr->result()));
1502
1503 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001504 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001505 } else {
1506 __ add(ToRegister(left), ToOperand(right));
1507 }
1508
1509 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1510 DeoptimizeIf(overflow, instr->environment());
1511 }
1512}
1513
1514
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001515void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
1516 LOperand* left = instr->InputAt(0);
1517 LOperand* right = instr->InputAt(1);
1518 ASSERT(left->Equals(instr->result()));
1519 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1520 if (instr->hydrogen()->representation().IsInteger32()) {
1521 Label return_left;
1522 Condition condition = (operation == HMathMinMax::kMathMin)
1523 ? less_equal
1524 : greater_equal;
1525 if (right->IsConstantOperand()) {
1526 Operand left_op = ToOperand(left);
1527 Immediate right_imm = ToInteger32Immediate(right);
1528 __ cmp(left_op, right_imm);
1529 __ j(condition, &return_left, Label::kNear);
1530 __ mov(left_op, right_imm);
1531 } else {
1532 Register left_reg = ToRegister(left);
1533 Operand right_op = ToOperand(right);
1534 __ cmp(left_reg, right_op);
1535 __ j(condition, &return_left, Label::kNear);
1536 __ mov(left_reg, right_op);
1537 }
1538 __ bind(&return_left);
1539 } else {
1540 ASSERT(instr->hydrogen()->representation().IsDouble());
1541 Label check_nan_left, check_zero, return_left, return_right;
1542 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1543 XMMRegister left_reg = ToDoubleRegister(left);
1544 XMMRegister right_reg = ToDoubleRegister(right);
1545 __ ucomisd(left_reg, right_reg);
1546 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1547 __ j(equal, &check_zero, Label::kNear); // left == right.
1548 __ j(condition, &return_left, Label::kNear);
1549 __ jmp(&return_right, Label::kNear);
1550
1551 __ bind(&check_zero);
1552 XMMRegister xmm_scratch = xmm0;
1553 __ xorps(xmm_scratch, xmm_scratch);
1554 __ ucomisd(left_reg, xmm_scratch);
1555 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1556 // At this point, both left and right are either 0 or -0.
1557 if (operation == HMathMinMax::kMathMin) {
1558 __ orpd(left_reg, right_reg);
1559 } else {
1560 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1561 __ addsd(left_reg, right_reg);
1562 }
1563 __ jmp(&return_left, Label::kNear);
1564
1565 __ bind(&check_nan_left);
1566 __ ucomisd(left_reg, left_reg); // NaN check.
1567 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1568 __ bind(&return_right);
1569 __ movsd(left_reg, right_reg);
1570
1571 __ bind(&return_left);
1572 }
1573}
1574
1575
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001576void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001577 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1578 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1579 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001581 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001582 switch (instr->op()) {
1583 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001584 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585 break;
1586 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001587 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001588 break;
1589 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001590 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001591 break;
1592 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001593 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001594 break;
1595 case Token::MOD: {
1596 // Pass two doubles as arguments on the stack.
1597 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001598 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1599 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001600 __ CallCFunction(
1601 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1602 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001603
1604 // Return value is in st(0) on ia32.
1605 // Store it into the (fixed) result register.
1606 __ sub(Operand(esp), Immediate(kDoubleSize));
1607 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001608 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609 __ add(Operand(esp), Immediate(kDoubleSize));
1610 break;
1611 }
1612 default:
1613 UNREACHABLE();
1614 break;
1615 }
1616}
1617
1618
1619void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001620 ASSERT(ToRegister(instr->context()).is(esi));
1621 ASSERT(ToRegister(instr->left()).is(edx));
1622 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001623 ASSERT(ToRegister(instr->result()).is(eax));
1624
danno@chromium.org40cb8782011-05-25 07:58:50 +00001625 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001626 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001627 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001628}
1629
1630
1631int LCodeGen::GetNextEmittedBlock(int block) {
1632 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1633 LLabel* label = chunk_->GetLabel(i);
1634 if (!label->HasReplacement()) return i;
1635 }
1636 return -1;
1637}
1638
1639
1640void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1641 int next_block = GetNextEmittedBlock(current_block_);
1642 right_block = chunk_->LookupDestination(right_block);
1643 left_block = chunk_->LookupDestination(left_block);
1644
1645 if (right_block == left_block) {
1646 EmitGoto(left_block);
1647 } else if (left_block == next_block) {
1648 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1649 } else if (right_block == next_block) {
1650 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1651 } else {
1652 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1653 __ jmp(chunk_->GetAssemblyLabel(right_block));
1654 }
1655}
1656
1657
1658void LCodeGen::DoBranch(LBranch* instr) {
1659 int true_block = chunk_->LookupDestination(instr->true_block_id());
1660 int false_block = chunk_->LookupDestination(instr->false_block_id());
1661
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001662 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001663 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001664 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001665 __ test(reg, Operand(reg));
1666 EmitBranch(true_block, false_block, not_zero);
1667 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001668 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001669 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001670 __ ucomisd(reg, xmm0);
1671 EmitBranch(true_block, false_block, not_equal);
1672 } else {
1673 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001674 Register reg = ToRegister(instr->InputAt(0));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001675 HType type = instr->hydrogen()->value()->type();
1676 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001679 } else if (type.IsSmi()) {
1680 __ test(reg, Operand(reg));
1681 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001682 } else {
1683 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1684 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1685
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001686 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1687 // Avoid deopts in the case where we've never executed this path before.
1688 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001689
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001690 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1691 // undefined -> false.
1692 __ cmp(reg, factory()->undefined_value());
1693 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001694 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001695 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1696 // true -> true.
1697 __ cmp(reg, factory()->true_value());
1698 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001699 // false -> false.
1700 __ cmp(reg, factory()->false_value());
1701 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001702 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001703 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1704 // 'null' -> false.
1705 __ cmp(reg, factory()->null_value());
1706 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001707 }
1708
1709 if (expected.Contains(ToBooleanStub::SMI)) {
1710 // Smis: 0 -> false, all other -> true.
1711 __ test(reg, Operand(reg));
1712 __ j(equal, false_label);
1713 __ JumpIfSmi(reg, true_label);
1714 } else if (expected.NeedsMap()) {
1715 // If we need a map later and have a Smi -> deopt.
1716 __ test(reg, Immediate(kSmiTagMask));
1717 DeoptimizeIf(zero, instr->environment());
1718 }
1719
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001720 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001721 if (expected.NeedsMap()) {
1722 map = ToRegister(instr->TempAt(0));
1723 ASSERT(!map.is(reg));
1724 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001725
1726 if (expected.CanBeUndetectable()) {
1727 // Undetectable -> false.
1728 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1729 1 << Map::kIsUndetectable);
1730 __ j(not_zero, false_label);
1731 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001732 }
1733
1734 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1735 // spec object -> true.
1736 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1737 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001738 }
1739
1740 if (expected.Contains(ToBooleanStub::STRING)) {
1741 // String value -> false iff empty.
1742 Label not_string;
1743 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1744 __ j(above_equal, &not_string, Label::kNear);
1745 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1746 __ j(not_zero, true_label);
1747 __ jmp(false_label);
1748 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001749 }
1750
1751 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1752 // heap number -> false iff +0, -0, or NaN.
1753 Label not_heap_number;
1754 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1755 factory()->heap_number_map());
1756 __ j(not_equal, &not_heap_number, Label::kNear);
1757 __ fldz();
1758 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1759 __ FCmp();
1760 __ j(zero, false_label);
1761 __ jmp(true_label);
1762 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001763 }
1764
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001765 // We've seen something for the first time -> deopt.
1766 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001767 }
1768 }
1769}
1770
1771
ager@chromium.org04921a82011-06-27 13:21:41 +00001772void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 block = chunk_->LookupDestination(block);
1774 int next_block = GetNextEmittedBlock(current_block_);
1775 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001776 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001777 }
1778}
1779
1780
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001781void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001782 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001783}
1784
1785
1786Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1787 Condition cond = no_condition;
1788 switch (op) {
1789 case Token::EQ:
1790 case Token::EQ_STRICT:
1791 cond = equal;
1792 break;
1793 case Token::LT:
1794 cond = is_unsigned ? below : less;
1795 break;
1796 case Token::GT:
1797 cond = is_unsigned ? above : greater;
1798 break;
1799 case Token::LTE:
1800 cond = is_unsigned ? below_equal : less_equal;
1801 break;
1802 case Token::GTE:
1803 cond = is_unsigned ? above_equal : greater_equal;
1804 break;
1805 case Token::IN:
1806 case Token::INSTANCEOF:
1807 default:
1808 UNREACHABLE();
1809 }
1810 return cond;
1811}
1812
1813
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001814void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001815 LOperand* left = instr->InputAt(0);
1816 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001817 int false_block = chunk_->LookupDestination(instr->false_block_id());
1818 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001819 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001820
1821 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1822 // We can statically evaluate the comparison.
1823 double left_val = ToDouble(LConstantOperand::cast(left));
1824 double right_val = ToDouble(LConstantOperand::cast(right));
1825 int next_block =
1826 EvalComparison(instr->op(), left_val, right_val) ? true_block
1827 : false_block;
1828 EmitGoto(next_block);
1829 } else {
1830 if (instr->is_double()) {
1831 // Don't base result on EFLAGS when a NaN is involved. Instead
1832 // jump to the false block.
1833 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1834 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1835 } else {
1836 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001837 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001838 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001839 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001840 // We transposed the operands. Reverse the condition.
1841 cc = ReverseCondition(cc);
1842 } else {
1843 __ cmp(ToRegister(left), ToOperand(right));
1844 }
1845 }
1846 EmitBranch(true_block, false_block, cc);
1847 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001848}
1849
1850
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001851void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001852 Register left = ToRegister(instr->InputAt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001853 Operand right = ToOperand(instr->InputAt(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001854 int false_block = chunk_->LookupDestination(instr->false_block_id());
1855 int true_block = chunk_->LookupDestination(instr->true_block_id());
1856
1857 __ cmp(left, Operand(right));
1858 EmitBranch(true_block, false_block, equal);
1859}
1860
1861
whesse@chromium.org7b260152011-06-20 15:33:18 +00001862void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
1863 Register left = ToRegister(instr->InputAt(0));
1864 int true_block = chunk_->LookupDestination(instr->true_block_id());
1865 int false_block = chunk_->LookupDestination(instr->false_block_id());
1866
1867 __ cmp(left, instr->hydrogen()->right());
1868 EmitBranch(true_block, false_block, equal);
1869}
1870
1871
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001872void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001873 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001874 int false_block = chunk_->LookupDestination(instr->false_block_id());
1875
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001876 // If the expression is known to be untagged or a smi, then it's definitely
1877 // not null, and it can't be a an undetectable object.
1878 if (instr->hydrogen()->representation().IsSpecialization() ||
1879 instr->hydrogen()->type().IsSmi()) {
1880 EmitGoto(false_block);
1881 return;
1882 }
1883
1884 int true_block = chunk_->LookupDestination(instr->true_block_id());
1885 Handle<Object> nil_value = instr->nil() == kNullValue ?
1886 factory()->null_value() :
1887 factory()->undefined_value();
1888 __ cmp(reg, nil_value);
1889 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 EmitBranch(true_block, false_block, equal);
1891 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001892 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
1893 factory()->undefined_value() :
1894 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001895 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1896 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1897 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001898 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001899 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001900 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 // Check for undetectable objects by looking in the bit field in
1902 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001903 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001904 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1905 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1906 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1907 EmitBranch(true_block, false_block, not_zero);
1908 }
1909}
1910
1911
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001912Condition LCodeGen::EmitIsObject(Register input,
1913 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001914 Label* is_not_object,
1915 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001916 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001918 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001919 __ j(equal, is_object);
1920
1921 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1922 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001923 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
1924 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001925 __ j(not_zero, is_not_object);
1926
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001927 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
1928 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001929 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001930 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001931 return below_equal;
1932}
1933
1934
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001935void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001936 Register reg = ToRegister(instr->InputAt(0));
1937 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001938
1939 int true_block = chunk_->LookupDestination(instr->true_block_id());
1940 int false_block = chunk_->LookupDestination(instr->false_block_id());
1941 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1942 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1943
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001944 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001945
1946 EmitBranch(true_block, false_block, true_cond);
1947}
1948
1949
erikcorry0ad885c2011-11-21 13:51:57 +00001950Condition LCodeGen::EmitIsString(Register input,
1951 Register temp1,
1952 Label* is_not_string) {
1953 __ JumpIfSmi(input, is_not_string);
1954
1955 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
1956
1957 return cond;
1958}
1959
1960
1961void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
1962 Register reg = ToRegister(instr->InputAt(0));
1963 Register temp = ToRegister(instr->TempAt(0));
1964
1965 int true_block = chunk_->LookupDestination(instr->true_block_id());
1966 int false_block = chunk_->LookupDestination(instr->false_block_id());
1967 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1968
1969 Condition true_cond = EmitIsString(reg, temp, false_label);
1970
1971 EmitBranch(true_block, false_block, true_cond);
1972}
1973
1974
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001976 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001977
1978 int true_block = chunk_->LookupDestination(instr->true_block_id());
1979 int false_block = chunk_->LookupDestination(instr->false_block_id());
1980
1981 __ test(input, Immediate(kSmiTagMask));
1982 EmitBranch(true_block, false_block, zero);
1983}
1984
1985
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001986void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1987 Register input = ToRegister(instr->InputAt(0));
1988 Register temp = ToRegister(instr->TempAt(0));
1989
1990 int true_block = chunk_->LookupDestination(instr->true_block_id());
1991 int false_block = chunk_->LookupDestination(instr->false_block_id());
1992
1993 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001994 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001995 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1996 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1997 1 << Map::kIsUndetectable);
1998 EmitBranch(true_block, false_block, not_zero);
1999}
2000
2001
erikcorry0ad885c2011-11-21 13:51:57 +00002002static Condition ComputeCompareCondition(Token::Value op) {
2003 switch (op) {
2004 case Token::EQ_STRICT:
2005 case Token::EQ:
2006 return equal;
2007 case Token::LT:
2008 return less;
2009 case Token::GT:
2010 return greater;
2011 case Token::LTE:
2012 return less_equal;
2013 case Token::GTE:
2014 return greater_equal;
2015 default:
2016 UNREACHABLE();
2017 return no_condition;
2018 }
2019}
2020
2021
2022void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2023 Token::Value op = instr->op();
2024 int true_block = chunk_->LookupDestination(instr->true_block_id());
2025 int false_block = chunk_->LookupDestination(instr->false_block_id());
2026
2027 Handle<Code> ic = CompareIC::GetUninitialized(op);
2028 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2029
2030 Condition condition = ComputeCompareCondition(op);
2031 __ test(eax, Operand(eax));
2032
2033 EmitBranch(true_block, false_block, condition);
2034}
2035
2036
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002037static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002038 InstanceType from = instr->from();
2039 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002040 if (from == FIRST_TYPE) return to;
2041 ASSERT(from == to || to == LAST_TYPE);
2042 return from;
2043}
2044
2045
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002046static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002047 InstanceType from = instr->from();
2048 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002049 if (from == to) return equal;
2050 if (to == LAST_TYPE) return above_equal;
2051 if (from == FIRST_TYPE) return below_equal;
2052 UNREACHABLE();
2053 return equal;
2054}
2055
2056
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002057void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002058 Register input = ToRegister(instr->InputAt(0));
2059 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002060
2061 int true_block = chunk_->LookupDestination(instr->true_block_id());
2062 int false_block = chunk_->LookupDestination(instr->false_block_id());
2063
2064 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2065
whesse@chromium.org7b260152011-06-20 15:33:18 +00002066 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002067
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002068 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2069 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002070}
2071
2072
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002073void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2074 Register input = ToRegister(instr->InputAt(0));
2075 Register result = ToRegister(instr->result());
2076
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002077 __ AbortIfNotString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002078
2079 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2080 __ IndexFromHash(result, result);
2081}
2082
2083
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002084void LCodeGen::DoHasCachedArrayIndexAndBranch(
2085 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002086 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002087
2088 int true_block = chunk_->LookupDestination(instr->true_block_id());
2089 int false_block = chunk_->LookupDestination(instr->false_block_id());
2090
2091 __ test(FieldOperand(input, String::kHashFieldOffset),
2092 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002093 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002094}
2095
2096
2097// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002098// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002099void LCodeGen::EmitClassOfTest(Label* is_true,
2100 Label* is_false,
2101 Handle<String>class_name,
2102 Register input,
2103 Register temp,
2104 Register temp2) {
2105 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002106 ASSERT(!input.is(temp2));
2107 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002108 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002109
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002110 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002111 // Assuming the following assertions, we can use the same compares to test
2112 // for both being a function type and being in the object type range.
2113 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2114 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2115 FIRST_SPEC_OBJECT_TYPE + 1);
2116 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2117 LAST_SPEC_OBJECT_TYPE - 1);
2118 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2119 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2120 __ j(below, is_false);
2121 __ j(equal, is_true);
2122 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2123 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002124 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002125 // Faster code path to avoid two compares: subtract lower bound from the
2126 // actual type and do a signed compare with the width of the type range.
2127 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002128 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002129 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002130 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2131 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002132 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002133 }
2134
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002135 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002136 // Check if the constructor in the map is a function.
2137 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002138 // Objects with a non-function constructor have class 'Object'.
2139 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
2140 if (class_name->IsEqualTo(CStrVector("Object"))) {
2141 __ j(not_equal, is_true);
2142 } else {
2143 __ j(not_equal, is_false);
2144 }
2145
2146 // temp now contains the constructor function. Grab the
2147 // instance class name from there.
2148 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2149 __ mov(temp, FieldOperand(temp,
2150 SharedFunctionInfo::kInstanceClassNameOffset));
2151 // The class name we are testing against is a symbol because it's a literal.
2152 // The name in the constructor is a symbol because of the way the context is
2153 // booted. This routine isn't expected to work for random API-created
2154 // classes and it doesn't have to because you can't access it with natives
2155 // syntax. Since both sides are symbols it is sufficient to use an identity
2156 // comparison.
2157 __ cmp(temp, class_name);
2158 // End with the answer in the z flag.
2159}
2160
2161
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002162void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002163 Register input = ToRegister(instr->InputAt(0));
2164 Register temp = ToRegister(instr->TempAt(0));
2165 Register temp2 = ToRegister(instr->TempAt(1));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002166
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002167 Handle<String> class_name = instr->hydrogen()->class_name();
2168
2169 int true_block = chunk_->LookupDestination(instr->true_block_id());
2170 int false_block = chunk_->LookupDestination(instr->false_block_id());
2171
2172 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2173 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2174
2175 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2176
2177 EmitBranch(true_block, false_block, equal);
2178}
2179
2180
2181void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002182 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002183 int true_block = instr->true_block_id();
2184 int false_block = instr->false_block_id();
2185
2186 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2187 EmitBranch(true_block, false_block, equal);
2188}
2189
2190
2191void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002192 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002193 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002194 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002195 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002196
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002197 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002198 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002199 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002201 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002202 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002204 __ bind(&done);
2205}
2206
2207
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002208void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2209 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2210 public:
2211 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2212 LInstanceOfKnownGlobal* instr)
2213 : LDeferredCode(codegen), instr_(instr) { }
2214 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002215 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002216 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002217 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002218 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002219 private:
2220 LInstanceOfKnownGlobal* instr_;
2221 Label map_check_;
2222 };
2223
2224 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002225 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002226
2227 Label done, false_result;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002228 Register object = ToRegister(instr->InputAt(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002229 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002230
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002231 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002232 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002233
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002234 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002235 // hole value will be patched to the last map/result pair generated by the
2236 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002237 Label cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002238 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002239 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2240 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002241 Handle<JSGlobalPropertyCell> cache_cell =
2242 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2243 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002244 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002246 __ jmp(&done);
2247
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002248 // The inlined call site cache did not match. Check for null and string
2249 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002250 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002251 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002252 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002253 __ j(equal, &false_result);
2254
2255 // String values are not instances of anything.
2256 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2257 __ j(is_string, &false_result);
2258
2259 // Go to the deferred code.
2260 __ jmp(deferred->entry());
2261
2262 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002263 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002264
2265 // Here result has either true or false. Deferred code also produces true or
2266 // false object.
2267 __ bind(deferred->exit());
2268 __ bind(&done);
2269}
2270
2271
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002272void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2273 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002274 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002275
2276 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2277 flags = static_cast<InstanceofStub::Flags>(
2278 flags | InstanceofStub::kArgsInRegisters);
2279 flags = static_cast<InstanceofStub::Flags>(
2280 flags | InstanceofStub::kCallSiteInlineCheck);
2281 flags = static_cast<InstanceofStub::Flags>(
2282 flags | InstanceofStub::kReturnTrueFalseObject);
2283 InstanceofStub stub(flags);
2284
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002285 // Get the temp register reserved by the instruction. This needs to be a
2286 // register which is pushed last by PushSafepointRegisters as top of the
2287 // stack is used to pass the offset to the location of the map check to
2288 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002289 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002290 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002291 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002292 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002293 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002294 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002295 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002296 CallCodeGeneric(stub.GetCode(),
2297 RelocInfo::CODE_TARGET,
2298 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002299 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002300 // Get the deoptimization index of the LLazyBailout-environment that
2301 // corresponds to this instruction.
2302 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002303 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2304
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002305 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002306 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002307}
2308
2309
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002310void LCodeGen::DoCmpT(LCmpT* instr) {
2311 Token::Value op = instr->op();
2312
2313 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002314 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002315
2316 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002317 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002318 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002319 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002320 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002321 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002322 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002323 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002324 __ bind(&done);
2325}
2326
2327
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002328void LCodeGen::DoReturn(LReturn* instr) {
2329 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002330 // Preserve the return value on the stack and rely on the runtime call
2331 // to return the value in the same register. We're leaving the code
2332 // managed by the register allocator and tearing down the frame, it's
2333 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002335 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002336 __ CallRuntime(Runtime::kTraceExit, 1);
2337 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002338 if (dynamic_frame_alignment_) {
2339 // Fetch the state of the dynamic frame alignment.
2340 __ mov(edx, Operand(ebp,
2341 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2342 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343 __ mov(esp, ebp);
2344 __ pop(ebp);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002345 if (dynamic_frame_alignment_) {
2346 Label no_padding;
2347 __ cmp(edx, Immediate(kNoAlignmentPadding));
2348 __ j(equal, &no_padding);
2349 if (FLAG_debug_code) {
2350 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2351 Immediate(kAlignmentZapValue));
2352 __ Assert(equal, "expected alignment marker");
2353 }
2354 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2355 __ bind(&no_padding);
2356 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00002357 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002358}
2359
2360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002361void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002362 Register result = ToRegister(instr->result());
2363 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002364 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002366 DeoptimizeIf(equal, instr->environment());
2367 }
2368}
2369
2370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002371void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2372 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002373 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002374 ASSERT(ToRegister(instr->result()).is(eax));
2375
2376 __ mov(ecx, instr->name());
2377 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2378 RelocInfo::CODE_TARGET_CONTEXT;
2379 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002380 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002381}
2382
2383
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002384void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002385 Register value = ToRegister(instr->value());
2386 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002387
2388 // If the cell we are storing to contains the hole it could have
2389 // been deleted from the property dictionary. In that case, we need
2390 // to update the property details in the property dictionary to mark
2391 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002392 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002393 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002394 DeoptimizeIf(equal, instr->environment());
2395 }
2396
2397 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002398 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002399 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002400}
2401
2402
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002403void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2404 ASSERT(ToRegister(instr->context()).is(esi));
2405 ASSERT(ToRegister(instr->global_object()).is(edx));
2406 ASSERT(ToRegister(instr->value()).is(eax));
2407
2408 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002409 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002410 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2411 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002412 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002413}
2414
2415
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002416void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002417 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002418 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002419 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002420
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002421 if (instr->hydrogen()->RequiresHoleCheck()) {
2422 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002423 if (instr->hydrogen()->DeoptimizesOnHole()) {
2424 DeoptimizeIf(equal, instr->environment());
2425 } else {
2426 Label is_not_hole;
2427 __ j(not_equal, &is_not_hole, Label::kNear);
2428 __ mov(result, factory()->undefined_value());
2429 __ bind(&is_not_hole);
2430 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002431 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002432}
2433
2434
2435void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2436 Register context = ToRegister(instr->context());
2437 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002438
2439 Label skip_assignment;
2440
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002441 Operand target = ContextOperand(context, instr->slot_index());
2442 if (instr->hydrogen()->RequiresHoleCheck()) {
2443 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002444 if (instr->hydrogen()->DeoptimizesOnHole()) {
2445 DeoptimizeIf(equal, instr->environment());
2446 } else {
2447 __ j(not_equal, &skip_assignment, Label::kNear);
2448 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002449 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002450
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002451 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002452 if (instr->hydrogen()->NeedsWriteBarrier()) {
2453 HType type = instr->hydrogen()->value()->type();
2454 SmiCheck check_needed =
2455 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002456 Register temp = ToRegister(instr->TempAt(0));
2457 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002458 __ RecordWriteContextSlot(context,
2459 offset,
2460 value,
2461 temp,
2462 kSaveFPRegs,
2463 EMIT_REMEMBERED_SET,
2464 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002465 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002466
2467 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002468}
2469
2470
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002471void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002472 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002473 Register result = ToRegister(instr->result());
2474 if (instr->hydrogen()->is_in_object()) {
2475 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2476 } else {
2477 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2478 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2479 }
2480}
2481
2482
lrn@chromium.org1c092762011-05-09 09:42:16 +00002483void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2484 Register object,
2485 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002486 Handle<String> name,
2487 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002488 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002489 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002490 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002491 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002492 int index = lookup.GetLocalFieldIndexFromMap(*type);
2493 int offset = index * kPointerSize;
2494 if (index < 0) {
2495 // Negative property indices are in-object properties, indexed
2496 // from the end of the fixed part of the object.
2497 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2498 } else {
2499 // Non-negative property indices are in the properties array.
2500 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2501 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2502 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002503 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002504 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002505 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002506 } else {
2507 // Negative lookup.
2508 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002509 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002510 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002511 while (*current != heap->null_value()) {
2512 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002513 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002514 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002515 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002516 current =
2517 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002518 }
2519 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002520 }
2521}
2522
2523
2524void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2525 ASSERT(!operand->IsDoubleRegister());
2526 if (operand->IsConstantOperand()) {
2527 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2528 if (object->IsSmi()) {
2529 __ Push(Handle<Smi>::cast(object));
2530 } else {
2531 __ PushHeapObject(Handle<HeapObject>::cast(object));
2532 }
2533 } else if (operand->IsRegister()) {
2534 __ push(ToRegister(operand));
2535 } else {
2536 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002537 }
2538}
2539
2540
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002541// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2542// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002543static bool CompactEmit(SmallMapList* list,
2544 Handle<String> name,
2545 int i,
2546 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002547 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002548 // If the map has ElementsKind transitions, we will generate map checks
2549 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002550 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002551 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002552 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002553 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002554}
2555
2556
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002557void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2558 Register object = ToRegister(instr->object());
2559 Register result = ToRegister(instr->result());
2560
2561 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002562 bool need_generic = instr->hydrogen()->need_generic();
2563
2564 if (map_count == 0 && !need_generic) {
2565 DeoptimizeIf(no_condition, instr->environment());
2566 return;
2567 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002568 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002569 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002570 bool all_are_compact = true;
2571 for (int i = 0; i < map_count; ++i) {
2572 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2573 all_are_compact = false;
2574 break;
2575 }
2576 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002577 for (int i = 0; i < map_count; ++i) {
2578 bool last = (i == map_count - 1);
2579 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002580 Label check_passed;
2581 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002582 if (last && !need_generic) {
2583 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002584 __ bind(&check_passed);
2585 EmitLoadFieldOrConstantFunction(
2586 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002587 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002588 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002589 bool compact = all_are_compact ? true :
2590 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
2591 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
2592 __ bind(&check_passed);
2593 EmitLoadFieldOrConstantFunction(
2594 result, object, map, name, instr->environment());
2595 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002596 __ bind(&next);
2597 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002598 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002599 if (need_generic) {
2600 __ mov(ecx, name);
2601 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2602 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2603 }
2604 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002605}
2606
2607
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002608void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002609 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002610 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002611 ASSERT(ToRegister(instr->result()).is(eax));
2612
2613 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002614 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002615 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002616}
2617
2618
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002619void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2620 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002621 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002622 Register result = ToRegister(instr->result());
2623
2624 // Check that the function really is a function.
2625 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2626 DeoptimizeIf(not_equal, instr->environment());
2627
2628 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002629 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002630 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2631 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002632 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002633
2634 // Get the prototype or initial map from the function.
2635 __ mov(result,
2636 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2637
2638 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002639 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002640 DeoptimizeIf(equal, instr->environment());
2641
2642 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002643 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002644 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002645 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002646
2647 // Get the prototype from the initial map.
2648 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002649 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002650
2651 // Non-instance prototype: Fetch prototype from constructor field
2652 // in the function's map.
2653 __ bind(&non_instance);
2654 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2655
2656 // All done.
2657 __ bind(&done);
2658}
2659
2660
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002661void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002662 Register result = ToRegister(instr->result());
2663 Register input = ToRegister(instr->InputAt(0));
2664 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002665 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002666 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002667 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002668 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002669 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002670 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002671 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002672 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002673 Register temp((result.is(eax)) ? ebx : eax);
2674 __ push(temp);
2675 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002676 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2677 __ and_(temp, Map::kElementsKindMask);
2678 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002679 __ cmp(temp, GetInitialFastElementsKind());
2680 __ j(less, &fail, Label::kNear);
2681 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
2682 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002683 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002684 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002685 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002686 __ j(less_equal, &ok, Label::kNear);
2687 __ bind(&fail);
2688 __ Abort("Check for fast or external elements failed.");
2689 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002690 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002691 __ bind(&done);
2692 }
2693}
2694
2695
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002696void LCodeGen::DoLoadExternalArrayPointer(
2697 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002698 Register result = ToRegister(instr->result());
2699 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002700 __ mov(result, FieldOperand(input,
2701 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002702}
2703
2704
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002705void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2706 Register arguments = ToRegister(instr->arguments());
2707 Register length = ToRegister(instr->length());
2708 Operand index = ToOperand(instr->index());
2709 Register result = ToRegister(instr->result());
2710
2711 __ sub(length, index);
2712 DeoptimizeIf(below_equal, instr->environment());
2713
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002714 // There are two words between the frame pointer and the last argument.
2715 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002716 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2717}
2718
2719
2720void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002721 Register result = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002722
2723 // Load the result.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002724 __ mov(result,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002725 BuildFastArrayOperand(instr->elements(),
2726 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002727 instr->hydrogen()->key()->representation(),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002728 FAST_ELEMENTS,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002729 FixedArray::kHeaderSize - kHeapObjectTag,
2730 instr->additional_index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002731
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002732 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002733 if (instr->hydrogen()->RequiresHoleCheck()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002734 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
2735 __ test(result, Immediate(kSmiTagMask));
2736 DeoptimizeIf(not_equal, instr->environment());
2737 } else {
2738 __ cmp(result, factory()->the_hole_value());
2739 DeoptimizeIf(equal, instr->environment());
2740 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002741 }
2742}
2743
2744
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002745void LCodeGen::DoLoadKeyedFastDoubleElement(
2746 LLoadKeyedFastDoubleElement* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002747 XMMRegister result = ToDoubleRegister(instr->result());
2748
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002749 if (instr->hydrogen()->RequiresHoleCheck()) {
2750 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2751 sizeof(kHoleNanLower32);
2752 Operand hole_check_operand = BuildFastArrayOperand(
2753 instr->elements(), instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002754 instr->hydrogen()->key()->representation(),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002755 FAST_DOUBLE_ELEMENTS,
2756 offset,
2757 instr->additional_index());
2758 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
2759 DeoptimizeIf(equal, instr->environment());
2760 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002761
2762 Operand double_load_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002763 instr->elements(),
2764 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002765 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002766 FAST_DOUBLE_ELEMENTS,
2767 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
2768 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002769 __ movdbl(result, double_load_operand);
2770}
2771
2772
2773Operand LCodeGen::BuildFastArrayOperand(
danno@chromium.orgb6451162011-08-17 14:33:23 +00002774 LOperand* elements_pointer,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002775 LOperand* key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002776 Representation key_representation,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002777 ElementsKind elements_kind,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002778 uint32_t offset,
2779 uint32_t additional_index) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00002780 Register elements_pointer_reg = ToRegister(elements_pointer);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002781 int shift_size = ElementsKindToShiftSize(elements_kind);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002782 // Even though the HLoad/StoreKeyedFastElement instructions force the input
2783 // representation for the key to be an integer, the input gets replaced during
2784 // bound check elimination with the index argument to the bounds check, which
2785 // can be tagged, so that case must be handled here, too.
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002786 if (key_representation.IsTagged() && (shift_size >= 1)) {
2787 shift_size -= kSmiTagSize;
2788 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002789 if (key->IsConstantOperand()) {
2790 int constant_value = ToInteger32(LConstantOperand::cast(key));
2791 if (constant_value & 0xF0000000) {
2792 Abort("array index constant value too big");
2793 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002794 return Operand(elements_pointer_reg,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002795 ((constant_value + additional_index) << shift_size)
2796 + offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002797 } else {
2798 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002799 return Operand(elements_pointer_reg,
2800 ToRegister(key),
2801 scale_factor,
2802 offset + (additional_index << shift_size));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002803 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002804}
2805
2806
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002807void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2808 LLoadKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002809 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002810 LOperand* key = instr->key();
2811 if (!key->IsConstantOperand() &&
2812 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
2813 elements_kind)) {
2814 __ SmiUntag(ToRegister(key));
2815 }
2816 Operand operand(BuildFastArrayOperand(
2817 instr->external_pointer(),
2818 key,
2819 instr->hydrogen()->key()->representation(),
2820 elements_kind,
2821 0,
2822 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002823 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002824 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002825 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002826 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002827 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002828 __ movdbl(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002829 } else {
2830 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002831 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002832 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002833 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002834 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002835 case EXTERNAL_PIXEL_ELEMENTS:
2836 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002837 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002838 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002839 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002840 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002841 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002842 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002843 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002844 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002845 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002846 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002847 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002848 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002849 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002850 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2851 __ test(result, Operand(result));
2852 DeoptimizeIf(negative, instr->environment());
2853 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002854 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002855 case EXTERNAL_FLOAT_ELEMENTS:
2856 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002857 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002858 case FAST_ELEMENTS:
2859 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002860 case FAST_HOLEY_SMI_ELEMENTS:
2861 case FAST_HOLEY_ELEMENTS:
2862 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002863 case DICTIONARY_ELEMENTS:
2864 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002865 UNREACHABLE();
2866 break;
2867 }
2868 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002869}
2870
2871
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002872void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002873 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002874 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002875 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002876
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002877 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002878 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002879}
2880
2881
2882void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2883 Register result = ToRegister(instr->result());
2884
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002885 if (instr->hydrogen()->from_inlined()) {
2886 __ lea(result, Operand(esp, -2 * kPointerSize));
2887 } else {
2888 // Check for arguments adapter frame.
2889 Label done, adapted;
2890 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2891 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2892 __ cmp(Operand(result),
2893 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2894 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002895
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002896 // No arguments adaptor frame.
2897 __ mov(result, Operand(ebp));
2898 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002899
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002900 // Arguments adaptor frame present.
2901 __ bind(&adapted);
2902 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002903
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002904 // Result is the frame pointer for the frame if not adapted and for the real
2905 // frame below the adaptor frame if adapted.
2906 __ bind(&done);
2907 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002908}
2909
2910
2911void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002912 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002913 Register result = ToRegister(instr->result());
2914
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002915 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002916
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002917 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002918 __ cmp(ebp, elem);
2919 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002920 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002921
2922 // Arguments adaptor frame present. Get argument length from there.
2923 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2924 __ mov(result, Operand(result,
2925 ArgumentsAdaptorFrameConstants::kLengthOffset));
2926 __ SmiUntag(result);
2927
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002928 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002929 __ bind(&done);
2930}
2931
2932
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002933void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002934 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002935 Register function = ToRegister(instr->function());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002936 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002937
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002938 // If the receiver is null or undefined, we have to pass the global
2939 // object as a receiver to normal functions. Values have to be
2940 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002941 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002942
2943 // Do not transform the receiver to object for strict mode
2944 // functions.
2945 __ mov(scratch,
2946 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2947 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
2948 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
2949 __ j(not_equal, &receiver_ok, Label::kNear);
2950
2951 // Do not transform the receiver to object for builtins.
2952 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
2953 1 << SharedFunctionInfo::kNativeBitWithinByte);
2954 __ j(not_equal, &receiver_ok, Label::kNear);
2955
2956 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002958 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002959 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002960 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002961
2962 // The receiver should be a JS object.
2963 __ test(receiver, Immediate(kSmiTagMask));
2964 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002965 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002966 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002967 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002968
2969 __ bind(&global_object);
2970 // TODO(kmillikin): We have a hydrogen value for the global object. See
2971 // if it's better to use it than to explicitly fetch it from the context
2972 // here.
2973 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002974 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002975 __ mov(receiver,
2976 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002977 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002978}
2979
2980
2981void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2982 Register receiver = ToRegister(instr->receiver());
2983 Register function = ToRegister(instr->function());
2984 Register length = ToRegister(instr->length());
2985 Register elements = ToRegister(instr->elements());
2986 ASSERT(receiver.is(eax)); // Used for parameter count.
2987 ASSERT(function.is(edi)); // Required by InvokeFunction.
2988 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002989
2990 // Copy the arguments to this function possibly from the
2991 // adaptor frame below it.
2992 const uint32_t kArgumentsLimit = 1 * KB;
2993 __ cmp(length, kArgumentsLimit);
2994 DeoptimizeIf(above, instr->environment());
2995
2996 __ push(receiver);
2997 __ mov(receiver, length);
2998
2999 // Loop through the arguments pushing them onto the execution
3000 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003001 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003002 // length is a small non-negative integer, due to the test above.
3003 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003004 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003005 __ bind(&loop);
3006 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3007 __ dec(length);
3008 __ j(not_zero, &loop);
3009
3010 // Invoke the function.
3011 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003012 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003013 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003014 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003015 SafepointGenerator safepoint_generator(
3016 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003017 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003018 __ InvokeFunction(function, actual, CALL_FUNCTION,
3019 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003020}
3021
3022
3023void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003024 LOperand* argument = instr->InputAt(0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003025 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003026}
3027
3028
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003029void LCodeGen::DoDrop(LDrop* instr) {
3030 __ Drop(instr->count());
3031}
3032
3033
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003034void LCodeGen::DoThisFunction(LThisFunction* instr) {
3035 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003036 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003037}
3038
3039
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003040void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003041 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003042 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003043}
3044
3045
3046void LCodeGen::DoOuterContext(LOuterContext* instr) {
3047 Register context = ToRegister(instr->context());
3048 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003049 __ mov(result,
3050 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003051}
3052
3053
yangguo@chromium.org56454712012-02-16 15:33:53 +00003054void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3055 ASSERT(ToRegister(instr->InputAt(0)).is(esi));
3056 __ push(esi); // The context is the first argument.
3057 __ push(Immediate(instr->hydrogen()->pairs()));
3058 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3059 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3060}
3061
3062
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003063void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3064 Register context = ToRegister(instr->context());
3065 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003066 __ mov(result,
3067 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003068}
3069
3070
3071void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003072 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003073 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003074 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003075}
3076
3077
3078void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3079 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003080 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003081 CallKind call_kind,
3082 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003083 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3084 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003085
3086 LPointerMap* pointers = instr->pointer_map();
3087 RecordPosition(pointers->position());
3088
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003089 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003090 if (edi_state == EDI_UNINITIALIZED) {
3091 __ LoadHeapObject(edi, function);
3092 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003093
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003094 // Change context.
3095 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003096
3097 // Set eax to arguments count if adaption is not needed. Assumes that eax
3098 // is available to write to at this point.
3099 if (!function->NeedsArgumentsAdaption()) {
3100 __ mov(eax, arity);
3101 }
3102
3103 // Invoke function directly.
3104 __ SetCallKind(ecx, call_kind);
3105 if (*function == *info()->closure()) {
3106 __ CallSelf();
3107 } else {
3108 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3109 }
3110 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3111 } else {
3112 // We need to adapt arguments.
3113 SafepointGenerator generator(
3114 this, pointers, Safepoint::kLazyDeopt);
3115 ParameterCount count(arity);
3116 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3117 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003118}
3119
3120
3121void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3122 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003123 CallKnownFunction(instr->function(),
3124 instr->arity(),
3125 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003126 CALL_AS_METHOD,
3127 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003128}
3129
3130
3131void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003132 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003133 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003134 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003135 DeoptimizeIf(not_equal, instr->environment());
3136
3137 Label done;
3138 Register tmp = input_reg.is(eax) ? ecx : eax;
3139 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3140
3141 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003142 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003143
3144 Label negative;
3145 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003146 // Check the sign of the argument. If the argument is positive, just
3147 // return it. We do not need to patch the stack since |input| and
3148 // |result| are the same register and |input| will be restored
3149 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003150 __ test(tmp, Immediate(HeapNumber::kSignMask));
3151 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003152 __ jmp(&done);
3153
3154 __ bind(&negative);
3155
3156 Label allocated, slow;
3157 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3158 __ jmp(&allocated);
3159
3160 // Slow case: Call the runtime system to do the number allocation.
3161 __ bind(&slow);
3162
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003163 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3164 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003165
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003166 // Set the pointer to the new heap number in tmp.
3167 if (!tmp.is(eax)) __ mov(tmp, eax);
3168
3169 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003170 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003171
3172 __ bind(&allocated);
3173 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3174 __ and_(tmp2, ~HeapNumber::kSignMask);
3175 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3176 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3177 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003178 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003179
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003180 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003181}
3182
3183
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003184void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003185 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003186 __ test(input_reg, Operand(input_reg));
3187 Label is_positive;
3188 __ j(not_sign, &is_positive);
3189 __ neg(input_reg);
3190 __ test(input_reg, Operand(input_reg));
3191 DeoptimizeIf(negative, instr->environment());
3192 __ bind(&is_positive);
3193}
3194
3195
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003196void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3197 // Class for deferred case.
3198 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3199 public:
3200 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3201 LUnaryMathOperation* instr)
3202 : LDeferredCode(codegen), instr_(instr) { }
3203 virtual void Generate() {
3204 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3205 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003206 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003207 private:
3208 LUnaryMathOperation* instr_;
3209 };
3210
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003211 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003212 Representation r = instr->hydrogen()->value()->representation();
3213
3214 if (r.IsDouble()) {
3215 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003216 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003217 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003218 __ subsd(scratch, input_reg);
3219 __ pand(input_reg, scratch);
3220 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003221 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003222 } else { // Tagged case.
3223 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003224 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003225 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003226 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003227 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003228 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003229 __ bind(deferred->exit());
3230 }
3231}
3232
3233
3234void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
3235 XMMRegister xmm_scratch = xmm0;
3236 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003237 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003238
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003239 if (CpuFeatures::IsSupported(SSE4_1)) {
3240 CpuFeatures::Scope scope(SSE4_1);
3241 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3242 // Deoptimize on negative zero.
3243 Label non_zero;
3244 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3245 __ ucomisd(input_reg, xmm_scratch);
3246 __ j(not_equal, &non_zero, Label::kNear);
3247 __ movmskpd(output_reg, input_reg);
3248 __ test(output_reg, Immediate(1));
3249 DeoptimizeIf(not_zero, instr->environment());
3250 __ bind(&non_zero);
3251 }
3252 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3253 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3254 // Overflow is signalled with minint.
3255 __ cmp(output_reg, 0x80000000u);
3256 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003257 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003258 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003259 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003260 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3261 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003262 DeoptimizeIf(parity_even, instr->environment());
3263 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003264
3265 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3266 // Check for negative zero.
3267 Label positive_sign;
3268 __ j(above, &positive_sign, Label::kNear);
3269 __ movmskpd(output_reg, input_reg);
3270 __ test(output_reg, Immediate(1));
3271 DeoptimizeIf(not_zero, instr->environment());
3272 __ Set(output_reg, Immediate(0));
3273 __ jmp(&done, Label::kNear);
3274 __ bind(&positive_sign);
3275 }
3276
3277 // Use truncating instruction (OK because input is positive).
3278 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003279 // Overflow is signalled with minint.
3280 __ cmp(output_reg, 0x80000000u);
3281 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003282 __ jmp(&done, Label::kNear);
3283
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003284 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003285 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003286 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003287 __ cvttsd2si(output_reg, Operand(input_reg));
3288 __ cvtsi2sd(xmm_scratch, output_reg);
3289 __ ucomisd(input_reg, xmm_scratch);
3290 __ j(equal, &done, Label::kNear);
3291 __ sub(output_reg, Immediate(1));
3292 DeoptimizeIf(overflow, instr->environment());
3293
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003294 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003295 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003296}
3297
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
3299 XMMRegister xmm_scratch = xmm0;
3300 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003301 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003302
danno@chromium.org160a7b02011-04-18 15:51:38 +00003303 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003304 // xmm_scratch = 0.5
3305 ExternalReference one_half = ExternalReference::address_of_one_half();
3306 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003307 __ ucomisd(xmm_scratch, input_reg);
3308 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003309 // xmm_scratch = input + 0.5
3310 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003311
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003312 // Compute Math.floor(value + 0.5).
3313 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003314 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003315
3316 // Overflow is signalled with minint.
3317 __ cmp(output_reg, 0x80000000u);
3318 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003319 __ jmp(&done);
3320
3321 __ bind(&below_half);
3322
3323 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3324 // we can ignore the difference between a result of -0 and +0.
3325 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3326 // If the sign is positive, we return +0.
3327 __ movmskpd(output_reg, input_reg);
3328 __ test(output_reg, Immediate(1));
3329 DeoptimizeIf(not_zero, instr->environment());
3330 } else {
3331 // If the input is >= -0.5, we return +0.
3332 __ mov(output_reg, Immediate(0xBF000000));
3333 __ movd(xmm_scratch, Operand(output_reg));
3334 __ cvtss2sd(xmm_scratch, xmm_scratch);
3335 __ ucomisd(input_reg, xmm_scratch);
3336 DeoptimizeIf(below, instr->environment());
3337 }
3338 __ Set(output_reg, Immediate(0));
3339 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003340}
3341
3342
3343void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003344 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003345 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3346 __ sqrtsd(input_reg, input_reg);
3347}
3348
3349
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003350void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003351 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003352 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003353 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003354 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003355
3356 // Note that according to ECMA-262 15.8.2.13:
3357 // Math.pow(-Infinity, 0.5) == Infinity
3358 // Math.sqrt(-Infinity) == NaN
3359 Label done, sqrt;
3360 // Check base for -Infinity. According to IEEE-754, single-precision
3361 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3362 __ mov(scratch, 0xFF800000);
3363 __ movd(xmm_scratch, scratch);
3364 __ cvtss2sd(xmm_scratch, xmm_scratch);
3365 __ ucomisd(input_reg, xmm_scratch);
3366 // Comparing -Infinity with NaN results in "unordered", which sets the
3367 // zero flag as if both were equal. However, it also sets the carry flag.
3368 __ j(not_equal, &sqrt, Label::kNear);
3369 __ j(carry, &sqrt, Label::kNear);
3370 // If input is -Infinity, return Infinity.
3371 __ xorps(input_reg, input_reg);
3372 __ subsd(input_reg, xmm_scratch);
3373 __ jmp(&done, Label::kNear);
3374
3375 // Square root.
3376 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003377 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003378 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003379 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003380 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003381}
3382
3383
3384void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003385 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003386 // Having marked this as a call, we can use any registers.
3387 // Just make sure that the input/output registers are the expected ones.
3388 ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
3389 ToDoubleRegister(instr->InputAt(1)).is(xmm1));
3390 ASSERT(!instr->InputAt(1)->IsRegister() ||
3391 ToRegister(instr->InputAt(1)).is(eax));
3392 ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
3393 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003395 if (exponent_type.IsTagged()) {
3396 Label no_deopt;
3397 __ JumpIfSmi(eax, &no_deopt);
3398 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003399 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003400 __ bind(&no_deopt);
3401 MathPowStub stub(MathPowStub::TAGGED);
3402 __ CallStub(&stub);
3403 } else if (exponent_type.IsInteger32()) {
3404 MathPowStub stub(MathPowStub::INTEGER);
3405 __ CallStub(&stub);
3406 } else {
3407 ASSERT(exponent_type.IsDouble());
3408 MathPowStub stub(MathPowStub::DOUBLE);
3409 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003410 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003411}
3412
3413
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003414void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003415 class DeferredDoRandom: public LDeferredCode {
3416 public:
3417 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3418 : LDeferredCode(codegen), instr_(instr) { }
3419 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3420 virtual LInstruction* instr() { return instr_; }
3421 private:
3422 LRandom* instr_;
3423 };
3424
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003425 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003426
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003427 // Having marked this instruction as a call we can use any
3428 // registers.
3429 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3430 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003431 // Assert that the register size is indeed the size of each seed.
3432 static const int kSeedSize = sizeof(uint32_t);
3433 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003434
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003435 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003436 static const int kRandomSeedOffset =
3437 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3438 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003439 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003440
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003441 // Load state[0].
3442 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3443 // If state[0] == 0, call runtime to initialize seeds.
3444 __ test(ecx, ecx);
3445 __ j(zero, deferred->entry());
3446 // Load state[1].
3447 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3448 // ecx: state[0]
3449 // eax: state[1]
3450
3451 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3452 __ movzx_w(edx, ecx);
3453 __ imul(edx, edx, 18273);
3454 __ shr(ecx, 16);
3455 __ add(ecx, edx);
3456 // Save state[0].
3457 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3458
3459 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3460 __ movzx_w(edx, eax);
3461 __ imul(edx, edx, 36969);
3462 __ shr(eax, 16);
3463 __ add(eax, edx);
3464 // Save state[1].
3465 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3466
3467 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3468 __ shl(ecx, 14);
3469 __ and_(eax, Immediate(0x3FFFF));
3470 __ add(eax, ecx);
3471
3472 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003473 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3474 // by computing:
3475 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3476 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3477 __ movd(xmm2, ebx);
3478 __ movd(xmm1, eax);
3479 __ cvtss2sd(xmm2, xmm2);
3480 __ xorps(xmm1, xmm2);
3481 __ subsd(xmm1, xmm2);
3482}
3483
3484
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003485void LCodeGen::DoDeferredRandom(LRandom* instr) {
3486 __ PrepareCallCFunction(1, ebx);
3487 __ mov(Operand(esp, 0), eax);
3488 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3489 // Return value is in eax.
3490}
3491
3492
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003493void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003494 ASSERT(instr->value()->Equals(instr->result()));
3495 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003496 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003497 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003498 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003499 __ j(above, &positive, Label::kNear);
3500 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003501 ExternalReference nan =
3502 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003503 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003504 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003505 __ bind(&zero);
3506 __ push(Immediate(0xFFF00000));
3507 __ push(Immediate(0));
3508 __ movdbl(input_reg, Operand(esp, 0));
3509 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003510 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003511 __ bind(&positive);
3512 __ fldln2();
3513 __ sub(Operand(esp), Immediate(kDoubleSize));
3514 __ movdbl(Operand(esp, 0), input_reg);
3515 __ fld_d(Operand(esp, 0));
3516 __ fyl2x();
3517 __ fstp_d(Operand(esp, 0));
3518 __ movdbl(input_reg, Operand(esp, 0));
3519 __ add(Operand(esp), Immediate(kDoubleSize));
3520 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003521}
3522
3523
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003524void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3525 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3526 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3527 TranscendentalCacheStub::UNTAGGED);
3528 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3529}
3530
3531
whesse@chromium.org023421e2010-12-21 12:19:12 +00003532void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3533 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3534 TranscendentalCacheStub stub(TranscendentalCache::COS,
3535 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003536 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003537}
3538
3539
3540void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3541 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3542 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3543 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003544 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003545}
3546
3547
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003548void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3549 switch (instr->op()) {
3550 case kMathAbs:
3551 DoMathAbs(instr);
3552 break;
3553 case kMathFloor:
3554 DoMathFloor(instr);
3555 break;
3556 case kMathRound:
3557 DoMathRound(instr);
3558 break;
3559 case kMathSqrt:
3560 DoMathSqrt(instr);
3561 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003562 case kMathCos:
3563 DoMathCos(instr);
3564 break;
3565 case kMathSin:
3566 DoMathSin(instr);
3567 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003568 case kMathTan:
3569 DoMathTan(instr);
3570 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003571 case kMathLog:
3572 DoMathLog(instr);
3573 break;
3574
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003575 default:
3576 UNREACHABLE();
3577 }
3578}
3579
3580
danno@chromium.org160a7b02011-04-18 15:51:38 +00003581void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3582 ASSERT(ToRegister(instr->context()).is(esi));
3583 ASSERT(ToRegister(instr->function()).is(edi));
3584 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003585
3586 if (instr->known_function().is_null()) {
3587 LPointerMap* pointers = instr->pointer_map();
3588 RecordPosition(pointers->position());
3589 SafepointGenerator generator(
3590 this, pointers, Safepoint::kLazyDeopt);
3591 ParameterCount count(instr->arity());
3592 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3593 } else {
3594 CallKnownFunction(instr->known_function(),
3595 instr->arity(),
3596 instr,
3597 CALL_AS_METHOD,
3598 EDI_CONTAINS_TARGET);
3599 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003600}
3601
3602
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003604 ASSERT(ToRegister(instr->context()).is(esi));
3605 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003606 ASSERT(ToRegister(instr->result()).is(eax));
3607
3608 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003609 Handle<Code> ic =
3610 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003611 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003612}
3613
3614
3615void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003616 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003617 ASSERT(ToRegister(instr->result()).is(eax));
3618
3619 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003620 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3621 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003622 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003623 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003624 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003625}
3626
3627
3628void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003629 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003630 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003631 ASSERT(ToRegister(instr->result()).is(eax));
3632
3633 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003634 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003635 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003636}
3637
3638
3639void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003640 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003641 ASSERT(ToRegister(instr->result()).is(eax));
3642
3643 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003644 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3645 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003646 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003647 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003648 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003649}
3650
3651
3652void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3653 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003654 CallKnownFunction(instr->target(),
3655 instr->arity(),
3656 instr,
3657 CALL_AS_FUNCTION,
3658 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003659}
3660
3661
3662void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003663 ASSERT(ToRegister(instr->context()).is(esi));
3664 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003665 ASSERT(ToRegister(instr->result()).is(eax));
3666
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003667 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003668 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003669 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003670}
3671
3672
3673void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003674 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003675}
3676
3677
3678void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3679 Register object = ToRegister(instr->object());
3680 Register value = ToRegister(instr->value());
3681 int offset = instr->offset();
3682
3683 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00003684 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
3685 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3686 } else {
3687 Register temp = ToRegister(instr->TempAt(0));
3688 Register temp_map = ToRegister(instr->TempAt(1));
3689 __ mov(temp_map, instr->transition());
3690 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
3691 // Update the write barrier for the map field.
3692 __ RecordWriteField(object,
3693 HeapObject::kMapOffset,
3694 temp_map,
3695 temp,
3696 kSaveFPRegs,
3697 OMIT_REMEMBERED_SET,
3698 OMIT_SMI_CHECK);
3699 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003700 }
3701
3702 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003703 HType type = instr->hydrogen()->value()->type();
3704 SmiCheck check_needed =
3705 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706 if (instr->is_in_object()) {
3707 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003708 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003709 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003710 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003711 __ RecordWriteField(object,
3712 offset,
3713 value,
3714 temp,
3715 kSaveFPRegs,
3716 EMIT_REMEMBERED_SET,
3717 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003718 }
3719 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003720 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003721 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3722 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003723 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003724 // Update the write barrier for the properties array.
3725 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003726 __ RecordWriteField(temp,
3727 offset,
3728 value,
3729 object,
3730 kSaveFPRegs,
3731 EMIT_REMEMBERED_SET,
3732 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003733 }
3734 }
3735}
3736
3737
3738void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003739 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003740 ASSERT(ToRegister(instr->object()).is(edx));
3741 ASSERT(ToRegister(instr->value()).is(eax));
3742
3743 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003744 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003745 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3746 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003747 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003748}
3749
3750
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003751void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
3752 HValue* value,
3753 LOperand* operand) {
3754 if (value->representation().IsTagged() && !value->type().IsSmi()) {
3755 if (operand->IsRegister()) {
3756 __ test(ToRegister(operand), Immediate(kSmiTagMask));
3757 } else {
3758 __ test(ToOperand(operand), Immediate(kSmiTagMask));
3759 }
3760 DeoptimizeIf(not_zero, environment);
3761 }
3762}
3763
3764
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003765void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003766 DeoptIfTaggedButNotSmi(instr->environment(),
3767 instr->hydrogen()->length(),
3768 instr->length());
3769 DeoptIfTaggedButNotSmi(instr->environment(),
3770 instr->hydrogen()->index(),
3771 instr->index());
danno@chromium.orgb6451162011-08-17 14:33:23 +00003772 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003773 int constant_index =
3774 ToInteger32(LConstantOperand::cast(instr->index()));
3775 if (instr->hydrogen()->length()->representation().IsTagged()) {
3776 __ cmp(ToOperand(instr->length()),
3777 Immediate(Smi::FromInt(constant_index)));
3778 } else {
3779 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
3780 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003781 DeoptimizeIf(below_equal, instr->environment());
3782 } else {
3783 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3784 DeoptimizeIf(above_equal, instr->environment());
3785 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003786}
3787
3788
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003789void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3790 LStoreKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003791 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003792 LOperand* key = instr->key();
3793 if (!key->IsConstantOperand() &&
3794 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3795 elements_kind)) {
3796 __ SmiUntag(ToRegister(key));
3797 }
3798 Operand operand(BuildFastArrayOperand(
3799 instr->external_pointer(),
3800 key,
3801 instr->hydrogen()->key()->representation(),
3802 elements_kind,
3803 0,
3804 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003805 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003806 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003807 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003808 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003809 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003810 } else {
3811 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003813 case EXTERNAL_PIXEL_ELEMENTS:
3814 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3815 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003816 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003817 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003818 case EXTERNAL_SHORT_ELEMENTS:
3819 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003820 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003821 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003822 case EXTERNAL_INT_ELEMENTS:
3823 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003824 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003825 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003826 case EXTERNAL_FLOAT_ELEMENTS:
3827 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003828 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003829 case FAST_ELEMENTS:
3830 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003831 case FAST_HOLEY_SMI_ELEMENTS:
3832 case FAST_HOLEY_ELEMENTS:
3833 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003834 case DICTIONARY_ELEMENTS:
3835 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003836 UNREACHABLE();
3837 break;
3838 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003839 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003840}
3841
3842
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003843void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3844 Register value = ToRegister(instr->value());
3845 Register elements = ToRegister(instr->object());
3846 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3847
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003848 Operand operand = BuildFastArrayOperand(
3849 instr->object(),
3850 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003851 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003852 FAST_ELEMENTS,
3853 FixedArray::kHeaderSize - kHeapObjectTag,
3854 instr->additional_index());
3855 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003856
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003857 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003858 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003859 HType type = instr->hydrogen()->value()->type();
3860 SmiCheck check_needed =
3861 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003862 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003863 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003864 __ RecordWrite(elements,
3865 key,
3866 value,
3867 kSaveFPRegs,
3868 EMIT_REMEMBERED_SET,
3869 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870 }
3871}
3872
3873
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003874void LCodeGen::DoStoreKeyedFastDoubleElement(
3875 LStoreKeyedFastDoubleElement* instr) {
3876 XMMRegister value = ToDoubleRegister(instr->value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003877
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003878 if (instr->NeedsCanonicalization()) {
3879 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003880
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003881 __ ucomisd(value, value);
3882 __ j(parity_odd, &have_value); // NaN.
3883
3884 ExternalReference canonical_nan_reference =
3885 ExternalReference::address_of_canonical_non_hole_nan();
3886 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
3887 __ bind(&have_value);
3888 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003889
3890 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003891 instr->elements(),
3892 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003893 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003894 FAST_DOUBLE_ELEMENTS,
3895 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3896 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003897 __ movdbl(double_store_operand, value);
3898}
3899
3900
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003901void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003902 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003903 ASSERT(ToRegister(instr->object()).is(edx));
3904 ASSERT(ToRegister(instr->key()).is(ecx));
3905 ASSERT(ToRegister(instr->value()).is(eax));
3906
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003907 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003908 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3909 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003910 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003911}
3912
3913
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003914void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
3915 Register object_reg = ToRegister(instr->object());
3916 Register new_map_reg = ToRegister(instr->new_map_reg());
3917
3918 Handle<Map> from_map = instr->original_map();
3919 Handle<Map> to_map = instr->transitioned_map();
3920 ElementsKind from_kind = from_map->elements_kind();
3921 ElementsKind to_kind = to_map->elements_kind();
3922
3923 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003924 bool is_simple_map_transition =
3925 IsSimpleMapChangeTransition(from_kind, to_kind);
3926 Label::Distance branch_distance =
3927 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003928 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003929 __ j(not_equal, &not_applicable, branch_distance);
3930 if (is_simple_map_transition) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003931 Register object_reg = ToRegister(instr->object());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003932 Handle<Map> map = instr->hydrogen()->transitioned_map();
3933 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
3934 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003935 // Write barrier.
3936 ASSERT_NE(instr->temp_reg(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003937 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
3938 ToRegister(instr->temp_reg()),
3939 kDontSaveFPRegs);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003940 } else if (IsFastSmiElementsKind(from_kind) &&
3941 IsFastDoubleElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003942 __ mov(new_map_reg, to_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003943 Register fixed_object_reg = ToRegister(instr->temp_reg());
3944 ASSERT(fixed_object_reg.is(edx));
3945 ASSERT(new_map_reg.is(ebx));
3946 __ mov(fixed_object_reg, object_reg);
3947 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
3948 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003949 } else if (IsFastDoubleElementsKind(from_kind) &&
3950 IsFastObjectElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003951 __ mov(new_map_reg, to_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003952 Register fixed_object_reg = ToRegister(instr->temp_reg());
3953 ASSERT(fixed_object_reg.is(edx));
3954 ASSERT(new_map_reg.is(ebx));
3955 __ mov(fixed_object_reg, object_reg);
3956 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
3957 RelocInfo::CODE_TARGET, instr);
3958 } else {
3959 UNREACHABLE();
3960 }
3961 __ bind(&not_applicable);
3962}
3963
3964
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003965void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3966 class DeferredStringCharCodeAt: public LDeferredCode {
3967 public:
3968 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3969 : LDeferredCode(codegen), instr_(instr) { }
3970 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003971 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003972 private:
3973 LStringCharCodeAt* instr_;
3974 };
3975
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003976 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003977 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003978
erikcorry0ad885c2011-11-21 13:51:57 +00003979 StringCharLoadGenerator::Generate(masm(),
3980 factory(),
3981 ToRegister(instr->string()),
3982 ToRegister(instr->index()),
3983 ToRegister(instr->result()),
3984 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003985 __ bind(deferred->exit());
3986}
3987
3988
3989void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3990 Register string = ToRegister(instr->string());
3991 Register result = ToRegister(instr->result());
3992
3993 // TODO(3095996): Get rid of this. For now, we need to make the
3994 // result register contain a valid pointer because it is already
3995 // contained in the register pointer map.
3996 __ Set(result, Immediate(0));
3997
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003998 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003999 __ push(string);
4000 // Push the index as a smi. This is safe because of the checks in
4001 // DoStringCharCodeAt above.
4002 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4003 if (instr->index()->IsConstantOperand()) {
4004 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4005 __ push(Immediate(Smi::FromInt(const_index)));
4006 } else {
4007 Register index = ToRegister(instr->index());
4008 __ SmiTag(index);
4009 __ push(index);
4010 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004011 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4012 instr, instr->context());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004013 if (FLAG_debug_code) {
4014 __ AbortIfNotSmi(eax);
4015 }
4016 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004017 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004018}
4019
4020
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004021void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4022 class DeferredStringCharFromCode: public LDeferredCode {
4023 public:
4024 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4025 : LDeferredCode(codegen), instr_(instr) { }
4026 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004027 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004028 private:
4029 LStringCharFromCode* instr_;
4030 };
4031
4032 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004033 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004034
4035 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4036 Register char_code = ToRegister(instr->char_code());
4037 Register result = ToRegister(instr->result());
4038 ASSERT(!char_code.is(result));
4039
4040 __ cmp(char_code, String::kMaxAsciiCharCode);
4041 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004043 __ mov(result, FieldOperand(result,
4044 char_code, times_pointer_size,
4045 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004046 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004047 __ j(equal, deferred->entry());
4048 __ bind(deferred->exit());
4049}
4050
4051
4052void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4053 Register char_code = ToRegister(instr->char_code());
4054 Register result = ToRegister(instr->result());
4055
4056 // TODO(3095996): Get rid of this. For now, we need to make the
4057 // result register contain a valid pointer because it is already
4058 // contained in the register pointer map.
4059 __ Set(result, Immediate(0));
4060
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004061 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004062 __ SmiTag(char_code);
4063 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004064 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004065 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004066}
4067
4068
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004069void LCodeGen::DoStringLength(LStringLength* instr) {
4070 Register string = ToRegister(instr->string());
4071 Register result = ToRegister(instr->result());
4072 __ mov(result, FieldOperand(string, String::kLengthOffset));
4073}
4074
4075
danno@chromium.org160a7b02011-04-18 15:51:38 +00004076void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004077 EmitPushTaggedOperand(instr->left());
4078 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004079 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004080 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004081}
4082
4083
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004084void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004085 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004086 ASSERT(input->IsRegister() || input->IsStackSlot());
4087 LOperand* output = instr->result();
4088 ASSERT(output->IsDoubleRegister());
4089 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4090}
4091
4092
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004093void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
4094 LOperand* input = instr->InputAt(0);
4095 LOperand* output = instr->result();
4096 LOperand* temp = instr->TempAt(0);
4097
4098 __ LoadUint32(ToDoubleRegister(output),
4099 ToRegister(input),
4100 ToDoubleRegister(temp));
4101}
4102
4103
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004104void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4105 class DeferredNumberTagI: public LDeferredCode {
4106 public:
4107 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4108 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004109 virtual void Generate() {
4110 codegen()->DoDeferredNumberTagI(instr_,
4111 instr_->InputAt(0),
4112 SIGNED_INT32);
4113 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004114 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004115 private:
4116 LNumberTagI* instr_;
4117 };
4118
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004119 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004120 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4121 Register reg = ToRegister(input);
4122
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004123 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004124 __ SmiTag(reg);
4125 __ j(overflow, deferred->entry());
4126 __ bind(deferred->exit());
4127}
4128
4129
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004130void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4131 class DeferredNumberTagU: public LDeferredCode {
4132 public:
4133 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4134 : LDeferredCode(codegen), instr_(instr) { }
4135 virtual void Generate() {
4136 codegen()->DoDeferredNumberTagI(instr_,
4137 instr_->InputAt(0),
4138 UNSIGNED_INT32);
4139 }
4140 virtual LInstruction* instr() { return instr_; }
4141 private:
4142 LNumberTagU* instr_;
4143 };
4144
4145 LOperand* input = instr->InputAt(0);
4146 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4147 Register reg = ToRegister(input);
4148
4149 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4150 __ cmp(reg, Immediate(Smi::kMaxValue));
4151 __ j(above, deferred->entry());
4152 __ SmiTag(reg);
4153 __ bind(deferred->exit());
4154}
4155
4156
4157void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4158 LOperand* value,
4159 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004160 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004161 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004162 Register tmp = reg.is(eax) ? ecx : eax;
4163
4164 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004165 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004166
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004167 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004168
4169 if (signedness == SIGNED_INT32) {
4170 // There was overflow, so bits 30 and 31 of the original integer
4171 // disagree. Try to allocate a heap number in new space and store
4172 // the value in there. If that fails, call the runtime system.
4173 __ SmiUntag(reg);
4174 __ xor_(reg, 0x80000000);
4175 __ cvtsi2sd(xmm0, Operand(reg));
4176 } else {
4177 __ LoadUint32(xmm0, reg, xmm1);
4178 }
4179
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004180 if (FLAG_inline_new) {
4181 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004182 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004183 }
4184
4185 // Slow case: Call the runtime system to do the number allocation.
4186 __ bind(&slow);
4187
4188 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4189 // register is stored, as this register is in the pointer map, but contains an
4190 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004191 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004192 // NumberTagI and NumberTagD use the context from the frame, rather than
4193 // the environment's HContext or HInlinedContext value.
4194 // They only call Runtime::kAllocateHeapNumber.
4195 // The corresponding HChange instructions are added in a phase that does
4196 // not have easy access to the local context.
4197 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4198 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4199 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004200 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004201 if (!reg.is(eax)) __ mov(reg, eax);
4202
4203 // Done. Put the value in xmm0 into the value of the allocated heap
4204 // number.
4205 __ bind(&done);
4206 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004207 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004208}
4209
4210
4211void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4212 class DeferredNumberTagD: public LDeferredCode {
4213 public:
4214 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4215 : LDeferredCode(codegen), instr_(instr) { }
4216 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004217 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004218 private:
4219 LNumberTagD* instr_;
4220 };
4221
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004222 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004223 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004224 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004225
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004226 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004227 if (FLAG_inline_new) {
4228 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4229 } else {
4230 __ jmp(deferred->entry());
4231 }
4232 __ bind(deferred->exit());
4233 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4234}
4235
4236
4237void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4238 // TODO(3095996): Get rid of this. For now, we need to make the
4239 // result register contain a valid pointer because it is already
4240 // contained in the register pointer map.
4241 Register reg = ToRegister(instr->result());
4242 __ Set(reg, Immediate(0));
4243
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004244 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004245 // NumberTagI and NumberTagD use the context from the frame, rather than
4246 // the environment's HContext or HInlinedContext value.
4247 // They only call Runtime::kAllocateHeapNumber.
4248 // The corresponding HChange instructions are added in a phase that does
4249 // not have easy access to the local context.
4250 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4251 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004252 RecordSafepointWithRegisters(
4253 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004254 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004255}
4256
4257
4258void LCodeGen::DoSmiTag(LSmiTag* 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() && input->Equals(instr->result()));
4261 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4262 __ SmiTag(ToRegister(input));
4263}
4264
4265
4266void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004267 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004268 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4269 if (instr->needs_check()) {
4270 __ test(ToRegister(input), Immediate(kSmiTagMask));
4271 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004272 } else {
4273 if (FLAG_debug_code) {
4274 __ AbortIfNotSmi(ToRegister(input));
4275 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004276 }
4277 __ SmiUntag(ToRegister(input));
4278}
4279
4280
4281void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004282 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004283 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004284 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004285 bool deoptimize_on_minus_zero,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004286 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004287 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004288
4289 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004290 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004291
4292 // Heap number map check.
4293 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004294 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004295 if (deoptimize_on_undefined) {
4296 DeoptimizeIf(not_equal, env);
4297 } else {
4298 Label heap_number;
4299 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004300
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004301 __ cmp(input_reg, factory()->undefined_value());
4302 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004303
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004304 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004305 ExternalReference nan =
4306 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004307 __ movdbl(result_reg, Operand::StaticVariable(nan));
4308 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004309
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004310 __ bind(&heap_number);
4311 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004312 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004313 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004314 if (deoptimize_on_minus_zero) {
4315 XMMRegister xmm_scratch = xmm0;
4316 __ xorps(xmm_scratch, xmm_scratch);
4317 __ ucomisd(result_reg, xmm_scratch);
4318 __ j(not_zero, &done, Label::kNear);
4319 __ movmskpd(temp_reg, result_reg);
4320 __ test_b(temp_reg, 1);
4321 DeoptimizeIf(not_zero, env);
4322 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004323 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004324
4325 // Smi to XMM conversion
4326 __ bind(&load_smi);
4327 __ SmiUntag(input_reg); // Untag smi before converting to float.
4328 __ cvtsi2sd(result_reg, Operand(input_reg));
4329 __ SmiTag(input_reg); // Retag smi.
4330 __ bind(&done);
4331}
4332
4333
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004334void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004335 Label done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004336 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004337
4338 // Heap number map check.
4339 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004340 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004341
4342 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004343 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004344 // Check for undefined. Undefined is converted to zero for truncating
4345 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004346 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004347 DeoptimizeIf(not_equal, instr->environment());
4348 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004349 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004350
4351 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004352 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004353 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004354 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004355 // Use more powerful conversion when sse3 is available.
4356 // Load x87 register with heap number.
4357 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4358 // Get exponent alone and check for too-big exponent.
4359 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
4360 __ and_(input_reg, HeapNumber::kExponentMask);
4361 const uint32_t kTooBigExponent =
4362 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4363 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004364 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004365 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004366 __ fstp(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004367 DeoptimizeIf(no_condition, instr->environment());
4368
4369 // Reserve space for 64 bit answer.
4370 __ bind(&convert);
4371 __ sub(Operand(esp), Immediate(kDoubleSize));
4372 // Do conversion, which cannot fail because we checked the exponent.
4373 __ fisttp_d(Operand(esp, 0));
4374 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
4375 __ add(Operand(esp), Immediate(kDoubleSize));
4376 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004377 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004378 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4379 __ cvttsd2si(input_reg, Operand(xmm0));
4380 __ cmp(input_reg, 0x80000000u);
4381 __ j(not_equal, &done);
4382 // Check if the input was 0x8000000 (kMinInt).
4383 // If no, then we got an overflow and we deoptimize.
4384 ExternalReference min_int = ExternalReference::address_of_min_int();
4385 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
4386 __ ucomisd(xmm_temp, xmm0);
4387 DeoptimizeIf(not_equal, instr->environment());
4388 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4389 }
4390 } else {
4391 // Deoptimize if we don't have a heap number.
4392 DeoptimizeIf(not_equal, instr->environment());
4393
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004394 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004395 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4396 __ cvttsd2si(input_reg, Operand(xmm0));
4397 __ cvtsi2sd(xmm_temp, Operand(input_reg));
4398 __ ucomisd(xmm0, xmm_temp);
4399 DeoptimizeIf(not_equal, instr->environment());
4400 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4401 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4402 __ test(input_reg, Operand(input_reg));
4403 __ j(not_zero, &done);
4404 __ movmskpd(input_reg, xmm0);
4405 __ and_(input_reg, 1);
4406 DeoptimizeIf(not_zero, instr->environment());
4407 }
4408 }
4409 __ bind(&done);
4410}
4411
4412
4413void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004414 class DeferredTaggedToI: public LDeferredCode {
4415 public:
4416 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4417 : LDeferredCode(codegen), instr_(instr) { }
4418 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4419 virtual LInstruction* instr() { return instr_; }
4420 private:
4421 LTaggedToI* instr_;
4422 };
4423
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004424 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004425 ASSERT(input->IsRegister());
4426 ASSERT(input->Equals(instr->result()));
4427
4428 Register input_reg = ToRegister(input);
4429
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004430 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004431
4432 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004433 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004434
4435 // Smi to int32 conversion
4436 __ SmiUntag(input_reg); // Untag smi.
4437
4438 __ bind(deferred->exit());
4439}
4440
4441
4442void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004443 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004444 ASSERT(input->IsRegister());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004445 LOperand* temp = instr->TempAt(0);
4446 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004447 LOperand* result = instr->result();
4448 ASSERT(result->IsDoubleRegister());
4449
4450 Register input_reg = ToRegister(input);
4451 XMMRegister result_reg = ToDoubleRegister(result);
4452
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004453 bool deoptimize_on_minus_zero =
4454 instr->hydrogen()->deoptimize_on_minus_zero();
4455 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
4456
4457 EmitNumberUntagD(input_reg,
4458 temp_reg,
4459 result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004460 instr->hydrogen()->deoptimize_on_undefined(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004461 deoptimize_on_minus_zero,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004462 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004463}
4464
4465
4466void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004467 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004468 ASSERT(input->IsDoubleRegister());
4469 LOperand* result = instr->result();
4470 ASSERT(result->IsRegister());
4471
4472 XMMRegister input_reg = ToDoubleRegister(input);
4473 Register result_reg = ToRegister(result);
4474
4475 if (instr->truncating()) {
4476 // Performs a truncating conversion of a floating point number as used by
4477 // the JS bitwise operations.
4478 __ cvttsd2si(result_reg, Operand(input_reg));
4479 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004480 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004481 // This will deoptimize if the exponent of the input in out of range.
4482 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004483 Label convert, done;
4484 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004485 __ sub(Operand(esp), Immediate(kDoubleSize));
4486 __ movdbl(Operand(esp, 0), input_reg);
4487 // Get exponent alone and check for too-big exponent.
4488 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
4489 __ and_(result_reg, HeapNumber::kExponentMask);
4490 const uint32_t kTooBigExponent =
4491 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4492 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004493 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004494 __ add(Operand(esp), Immediate(kDoubleSize));
4495 DeoptimizeIf(no_condition, instr->environment());
4496 __ bind(&convert);
4497 // Do conversion, which cannot fail because we checked the exponent.
4498 __ fld_d(Operand(esp, 0));
4499 __ fisttp_d(Operand(esp, 0));
4500 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
4501 __ add(Operand(esp), Immediate(kDoubleSize));
4502 __ bind(&done);
4503 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004504 Label done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004505 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004506 XMMRegister xmm_scratch = xmm0;
4507
4508 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
4509 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004510 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004511
4512 // Get high 32 bits of the input in result_reg and temp_reg.
4513 __ pshufd(xmm_scratch, input_reg, 1);
4514 __ movd(Operand(temp_reg), xmm_scratch);
4515 __ mov(result_reg, temp_reg);
4516
4517 // Prepare negation mask in temp_reg.
4518 __ sar(temp_reg, kBitsPerInt - 1);
4519
4520 // Extract the exponent from result_reg and subtract adjusted
4521 // bias from it. The adjustment is selected in a way such that
4522 // when the difference is zero, the answer is in the low 32 bits
4523 // of the input, otherwise a shift has to be performed.
4524 __ shr(result_reg, HeapNumber::kExponentShift);
4525 __ and_(result_reg,
4526 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
4527 __ sub(Operand(result_reg),
4528 Immediate(HeapNumber::kExponentBias +
4529 HeapNumber::kExponentBits +
4530 HeapNumber::kMantissaBits));
4531 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
4532 // special exponents.
4533 DeoptimizeIf(greater, instr->environment());
4534
4535 // Zero out the sign and the exponent in the input (by shifting
4536 // it to the left) and restore the implicit mantissa bit,
4537 // i.e. convert the input to unsigned int64 shifted left by
4538 // kExponentBits.
4539 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
4540 // Minus zero has the most significant bit set and the other
4541 // bits cleared.
4542 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
4543 __ psllq(input_reg, HeapNumber::kExponentBits);
4544 __ por(input_reg, xmm_scratch);
4545
4546 // Get the amount to shift the input right in xmm_scratch.
4547 __ neg(result_reg);
4548 __ movd(xmm_scratch, Operand(result_reg));
4549
4550 // Shift the input right and extract low 32 bits.
4551 __ psrlq(input_reg, xmm_scratch);
4552 __ movd(Operand(result_reg), input_reg);
4553
4554 // Use the prepared mask in temp_reg to negate the result if necessary.
4555 __ xor_(result_reg, Operand(temp_reg));
4556 __ sub(result_reg, Operand(temp_reg));
4557 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004558 }
4559 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004560 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004561 __ cvttsd2si(result_reg, Operand(input_reg));
4562 __ cvtsi2sd(xmm0, Operand(result_reg));
4563 __ ucomisd(xmm0, input_reg);
4564 DeoptimizeIf(not_equal, instr->environment());
4565 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4566 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4567 // The integer converted back is equal to the original. We
4568 // only have to test if we got -0 as an input.
4569 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004570 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004571 __ movmskpd(result_reg, input_reg);
4572 // Bit 0 contains the sign of the double in input_reg.
4573 // If input was positive, we are ok and return 0, otherwise
4574 // deoptimize.
4575 __ and_(result_reg, 1);
4576 DeoptimizeIf(not_zero, instr->environment());
4577 }
4578 __ bind(&done);
4579 }
4580}
4581
4582
4583void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004584 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004585 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004586 DeoptimizeIf(not_zero, instr->environment());
4587}
4588
4589
4590void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
4591 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004592 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004593 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004594}
4595
4596
4597void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004598 Register input = ToRegister(instr->InputAt(0));
4599 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004601 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004602
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004603 if (instr->hydrogen()->is_interval_check()) {
4604 InstanceType first;
4605 InstanceType last;
4606 instr->hydrogen()->GetCheckInterval(&first, &last);
4607
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004608 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4609 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004610
4611 // If there is only one type in the interval check for equality.
4612 if (first == last) {
4613 DeoptimizeIf(not_equal, instr->environment());
4614 } else {
4615 DeoptimizeIf(below, instr->environment());
4616 // Omit check for the last type.
4617 if (last != LAST_TYPE) {
4618 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4619 static_cast<int8_t>(last));
4620 DeoptimizeIf(above, instr->environment());
4621 }
4622 }
4623 } else {
4624 uint8_t mask;
4625 uint8_t tag;
4626 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4627
4628 if (IsPowerOf2(mask)) {
4629 ASSERT(tag == 0 || IsPowerOf2(tag));
4630 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
4631 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4632 } else {
4633 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4634 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004635 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004636 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004637 }
4638 }
4639}
4640
4641
4642void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004643 Handle<JSFunction> target = instr->hydrogen()->target();
4644 if (isolate()->heap()->InNewSpace(*target)) {
4645 Register reg = ToRegister(instr->value());
4646 Handle<JSGlobalPropertyCell> cell =
4647 isolate()->factory()->NewJSGlobalPropertyCell(target);
4648 __ cmp(reg, Operand::Cell(cell));
4649 } else {
4650 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004651 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004652 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004653 DeoptimizeIf(not_equal, instr->environment());
4654}
4655
4656
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004657void LCodeGen::DoCheckMapCommon(Register reg,
4658 Handle<Map> map,
4659 CompareMapMode mode,
4660 LEnvironment* env) {
4661 Label success;
4662 __ CompareMap(reg, map, &success, mode);
4663 DeoptimizeIf(not_equal, env);
4664 __ bind(&success);
4665}
4666
4667
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004668void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004669 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004670 ASSERT(input->IsRegister());
4671 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004672
4673 Label success;
4674 SmallMapList* map_set = instr->hydrogen()->map_set();
4675 for (int i = 0; i < map_set->length() - 1; i++) {
4676 Handle<Map> map = map_set->at(i);
4677 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
4678 __ j(equal, &success);
4679 }
4680 Handle<Map> map = map_set->last();
4681 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
4682 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004683}
4684
4685
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004686void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4687 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4688 Register result_reg = ToRegister(instr->result());
4689 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4690}
4691
4692
4693void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4694 ASSERT(instr->unclamped()->Equals(instr->result()));
4695 Register value_reg = ToRegister(instr->result());
4696 __ ClampUint8(value_reg);
4697}
4698
4699
4700void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4701 ASSERT(instr->unclamped()->Equals(instr->result()));
4702 Register input_reg = ToRegister(instr->unclamped());
4703 Label is_smi, done, heap_number;
4704
4705 __ JumpIfSmi(input_reg, &is_smi);
4706
4707 // Check for heap number
4708 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4709 factory()->heap_number_map());
4710 __ j(equal, &heap_number, Label::kNear);
4711
4712 // Check for undefined. Undefined is converted to zero for clamping
4713 // conversions.
4714 __ cmp(input_reg, factory()->undefined_value());
4715 DeoptimizeIf(not_equal, instr->environment());
4716 __ mov(input_reg, 0);
4717 __ jmp(&done, Label::kNear);
4718
4719 // Heap number
4720 __ bind(&heap_number);
4721 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4722 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4723 __ jmp(&done, Label::kNear);
4724
4725 // smi
4726 __ bind(&is_smi);
4727 __ SmiUntag(input_reg);
4728 __ ClampUint8(input_reg);
4729
4730 __ bind(&done);
4731}
4732
4733
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004734void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004735 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004736
4737 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004738 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004739
4740 // Load prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004741 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004742
4743 // Check prototype maps up to the holder.
4744 while (!current_prototype.is_identical_to(holder)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004745 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4746 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4747
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004748 current_prototype =
4749 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4750 // Load next prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004751 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004752 }
4753
4754 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004755 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4756 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757}
4758
4759
ulan@chromium.org967e2702012-02-28 09:49:15 +00004760void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
4761 class DeferredAllocateObject: public LDeferredCode {
4762 public:
4763 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
4764 : LDeferredCode(codegen), instr_(instr) { }
4765 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
4766 virtual LInstruction* instr() { return instr_; }
4767 private:
4768 LAllocateObject* instr_;
4769 };
4770
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004771 DeferredAllocateObject* deferred =
4772 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004773
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004774 Register result = ToRegister(instr->result());
4775 Register scratch = ToRegister(instr->TempAt(0));
4776 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4777 Handle<Map> initial_map(constructor->initial_map());
4778 int instance_size = initial_map->instance_size();
4779 ASSERT(initial_map->pre_allocated_property_fields() +
4780 initial_map->unused_property_fields() -
4781 initial_map->inobject_properties() == 0);
4782
4783 // Allocate memory for the object. The initial map might change when
4784 // the constructor's prototype changes, but instance size and property
4785 // counts remain unchanged (if slack tracking finished).
4786 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
4787 __ AllocateInNewSpace(instance_size,
4788 result,
4789 no_reg,
4790 scratch,
4791 deferred->entry(),
4792 TAG_OBJECT);
4793
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004794 __ bind(deferred->exit());
4795 if (FLAG_debug_code) {
4796 Label is_in_new_space;
4797 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
4798 __ Abort("Allocated object is not in new-space");
4799 __ bind(&is_in_new_space);
4800 }
4801
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004802 // Load the initial map.
4803 Register map = scratch;
4804 __ LoadHeapObject(scratch, constructor);
4805 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
4806
4807 if (FLAG_debug_code) {
4808 __ AbortIfSmi(map);
4809 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
4810 instance_size >> kPointerSizeLog2);
4811 __ Assert(equal, "Unexpected instance size");
4812 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
4813 initial_map->pre_allocated_property_fields());
4814 __ Assert(equal, "Unexpected pre-allocated property fields count");
4815 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
4816 initial_map->unused_property_fields());
4817 __ Assert(equal, "Unexpected unused property fields count");
4818 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
4819 initial_map->inobject_properties());
4820 __ Assert(equal, "Unexpected in-object property fields count");
4821 }
4822
4823 // Initialize map and fields of the newly allocated object.
4824 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
4825 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
4826 __ mov(scratch, factory()->empty_fixed_array());
4827 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
4828 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
4829 if (initial_map->inobject_properties() != 0) {
4830 __ mov(scratch, factory()->undefined_value());
4831 for (int i = 0; i < initial_map->inobject_properties(); i++) {
4832 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
4833 __ mov(FieldOperand(result, property_offset), scratch);
4834 }
4835 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00004836}
4837
4838
4839void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
4840 Register result = ToRegister(instr->result());
4841 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004842 Handle<Map> initial_map(constructor->initial_map());
4843 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00004844
4845 // TODO(3095996): Get rid of this. For now, we need to make the
4846 // result register contain a valid pointer because it is already
4847 // contained in the register pointer map.
4848 __ Set(result, Immediate(0));
4849
4850 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004851 __ push(Immediate(Smi::FromInt(instance_size)));
4852 CallRuntimeFromDeferred(
4853 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00004854 __ StoreToSafepointRegisterSlot(result, eax);
4855}
4856
4857
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004858void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004859 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004860 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004861 ElementsKind boilerplate_elements_kind =
4862 instr->hydrogen()->boilerplate_elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004863
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004864 // Deopt if the array literal boilerplate ElementsKind is of a type different
4865 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004866 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
4867 if (CanTransitionToMoreGeneralFastElementsKind(
4868 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004869 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
4870 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
4871 // Load the map's "bit field 2". We only need the first byte,
4872 // but the following masking takes care of that anyway.
4873 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
4874 // Retrieve elements_kind from bit field 2.
4875 __ and_(ebx, Map::kElementsKindMask);
4876 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
4877 DeoptimizeIf(not_equal, instr->environment());
4878 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004879
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004880 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004881 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004882 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004883 // Boilerplate already exists, constant elements are never accessed.
4884 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004885 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004886
4887 // Pick the right runtime function or stub to call.
4888 int length = instr->hydrogen()->length();
4889 if (instr->hydrogen()->IsCopyOnWrite()) {
4890 ASSERT(instr->hydrogen()->depth() == 1);
4891 FastCloneShallowArrayStub::Mode mode =
4892 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4893 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004894 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004895 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004896 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004897 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004898 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004899 } else {
4900 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004901 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
4902 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4903 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004904 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004905 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004906 }
4907}
4908
4909
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004910void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
4911 Register result,
4912 Register source,
4913 int* offset) {
4914 ASSERT(!source.is(ecx));
4915 ASSERT(!result.is(ecx));
4916
4917 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004918 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004919 __ cmp(source, ecx);
4920 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00004921 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
4922 __ cmp(ecx, Handle<Map>(object->map()));
4923 __ Assert(equal, "Unexpected boilerplate map");
4924 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
4925 __ and_(ecx, Map::kElementsKindMask);
4926 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
4927 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004928 }
4929
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004930 // Only elements backing stores for non-COW arrays need to be copied.
4931 Handle<FixedArrayBase> elements(object->elements());
4932 bool has_elements = elements->length() > 0 &&
4933 elements->map() != isolate()->heap()->fixed_cow_array_map();
4934
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004935 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004936 // this object and its backing store.
4937 int object_offset = *offset;
4938 int object_size = object->map()->instance_size();
4939 int elements_offset = *offset + object_size;
4940 int elements_size = has_elements ? elements->Size() : 0;
4941 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004942
4943 // Copy object header.
4944 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004945 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004946 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004947 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004948 if (has_elements && i == JSObject::kElementsOffset) {
4949 __ lea(ecx, Operand(result, elements_offset));
4950 } else {
4951 __ mov(ecx, FieldOperand(source, i));
4952 }
4953 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004954 }
4955
4956 // Copy in-object properties.
4957 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004958 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004959 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
4960 if (value->IsJSObject()) {
4961 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4962 __ lea(ecx, Operand(result, *offset));
4963 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004964 __ LoadHeapObject(source, value_object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004965 EmitDeepCopy(value_object, result, source, offset);
4966 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004967 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004968 __ mov(FieldOperand(result, total_offset), ecx);
4969 } else {
4970 __ mov(FieldOperand(result, total_offset), Immediate(value));
4971 }
4972 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004973
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004974 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004975 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004976 __ LoadHeapObject(source, elements);
4977 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
4978 __ mov(ecx, FieldOperand(source, i));
4979 __ mov(FieldOperand(result, elements_offset + i), ecx);
4980 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004981
danno@chromium.org88aa0582012-03-23 15:11:57 +00004982 // Copy elements backing store content.
4983 int elements_length = elements->length();
4984 if (elements->IsFixedDoubleArray()) {
4985 Handle<FixedDoubleArray> double_array =
4986 Handle<FixedDoubleArray>::cast(elements);
4987 for (int i = 0; i < elements_length; i++) {
4988 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004989 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
4990 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004991 int total_offset =
4992 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
4993 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
4994 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
4995 }
4996 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004997 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004998 for (int i = 0; i < elements_length; i++) {
4999 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005000 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00005001 if (value->IsJSObject()) {
5002 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5003 __ lea(ecx, Operand(result, *offset));
5004 __ mov(FieldOperand(result, total_offset), ecx);
5005 __ LoadHeapObject(source, value_object);
5006 EmitDeepCopy(value_object, result, source, offset);
5007 } else if (value->IsHeapObject()) {
5008 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5009 __ mov(FieldOperand(result, total_offset), ecx);
5010 } else {
5011 __ mov(FieldOperand(result, total_offset), Immediate(value));
5012 }
5013 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005014 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005015 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005016 }
5017 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005018}
5019
5020
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005021void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005022 ASSERT(ToRegister(instr->context()).is(esi));
5023 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005024 ElementsKind boilerplate_elements_kind =
5025 instr->hydrogen()->boilerplate()->GetElementsKind();
5026
5027 // Deopt if the literal boilerplate ElementsKind is of a type different than
5028 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005029 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5030 if (CanTransitionToMoreGeneralFastElementsKind(
5031 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005032 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5033 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5034 // Load the map's "bit field 2". We only need the first byte,
5035 // but the following masking takes care of that anyway.
5036 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5037 // Retrieve elements_kind from bit field 2.
5038 __ and_(ecx, Map::kElementsKindMask);
5039 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5040 DeoptimizeIf(not_equal, instr->environment());
5041 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005042
5043 // Allocate all objects that are part of the literal in one big
5044 // allocation. This avoids multiple limit checks.
5045 Label allocated, runtime_allocate;
5046 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5047 __ jmp(&allocated);
5048
5049 __ bind(&runtime_allocate);
5050 __ push(Immediate(Smi::FromInt(size)));
5051 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5052
5053 __ bind(&allocated);
5054 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005055 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005056 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset);
5057 ASSERT_EQ(size, offset);
5058}
5059
5060
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005061void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005062 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005063 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005064 Handle<FixedArray> constant_properties =
5065 instr->hydrogen()->constant_properties();
5066
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005067 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005068 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005070 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 int flags = instr->hydrogen()->fast_elements()
5072 ? ObjectLiteral::kFastElements
5073 : ObjectLiteral::kNoFlags;
5074 flags |= instr->hydrogen()->has_function()
5075 ? ObjectLiteral::kHasFunction
5076 : ObjectLiteral::kNoFlags;
5077 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005078
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005079 // Pick the right runtime function or stub to call.
5080 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005081 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005082 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005083 } else if (flags != ObjectLiteral::kFastElements ||
5084 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005085 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005086 } else {
5087 FastCloneShallowObjectStub stub(properties_count);
5088 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005089 }
5090}
5091
5092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
5094 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
5095 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005096 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097}
5098
5099
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005100void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005101 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005102 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005103 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005104 // ecx = literals array.
5105 // ebx = regexp literal.
5106 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005107 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005108 int literal_offset =
5109 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5110 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005111 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005113 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114
5115 // Create regexp literal using runtime function
5116 // Result will be in eax.
5117 __ push(ecx);
5118 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5119 __ push(Immediate(instr->hydrogen()->pattern()));
5120 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005121 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005122 __ mov(ebx, eax);
5123
5124 __ bind(&materialized);
5125 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5126 Label allocated, runtime_allocate;
5127 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5128 __ jmp(&allocated);
5129
5130 __ bind(&runtime_allocate);
5131 __ push(ebx);
5132 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005133 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005134 __ pop(ebx);
5135
5136 __ bind(&allocated);
5137 // Copy the content into the newly allocated memory.
5138 // (Unroll copy loop once for better throughput).
5139 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5140 __ mov(edx, FieldOperand(ebx, i));
5141 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5142 __ mov(FieldOperand(eax, i), edx);
5143 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5144 }
5145 if ((size % (2 * kPointerSize)) != 0) {
5146 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5147 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5148 }
5149}
5150
5151
5152void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005153 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005154 // Use the fast case closure allocation code that allocates in new
5155 // space for nested functions that don't need literals cloning.
5156 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005157 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005158 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005159 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005160 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005161 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005162 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005163 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005164 __ push(Immediate(shared_info));
5165 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 ? factory()->true_value()
5167 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005168 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005169 }
5170}
5171
5172
5173void LCodeGen::DoTypeof(LTypeof* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005174 LOperand* input = instr->InputAt(1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005175 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005176 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005177}
5178
5179
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005180void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00005181 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005182 int true_block = chunk_->LookupDestination(instr->true_block_id());
5183 int false_block = chunk_->LookupDestination(instr->false_block_id());
5184 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5185 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5186
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005187 Condition final_branch_condition =
5188 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5189 if (final_branch_condition != no_condition) {
5190 EmitBranch(true_block, false_block, final_branch_condition);
5191 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005192}
5193
5194
5195Condition LCodeGen::EmitTypeofIs(Label* true_label,
5196 Label* false_label,
5197 Register input,
5198 Handle<String> type_name) {
5199 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005201 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005202 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005204 final_branch_condition = equal;
5205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005207 __ JumpIfSmi(input, false_label);
5208 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5209 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005210 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5211 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005212 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005213
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005214 } else if (type_name->Equals(heap()->boolean_symbol())) {
5215 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005216 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005218 final_branch_condition = equal;
5219
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005220 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
5221 __ cmp(input, factory()->null_value());
5222 final_branch_condition = equal;
5223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224 } else if (type_name->Equals(heap()->undefined_symbol())) {
5225 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005227 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005228 // Check for undetectable objects => true.
5229 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5230 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5231 1 << Map::kIsUndetectable);
5232 final_branch_condition = not_zero;
5233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005234 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005235 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005236 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005237 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5238 __ j(equal, true_label);
5239 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5240 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005242 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005243 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005244 if (!FLAG_harmony_typeof) {
5245 __ cmp(input, factory()->null_value());
5246 __ j(equal, true_label);
5247 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005248 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005249 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005250 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5251 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005252 // Check for undetectable objects => false.
5253 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5254 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005255 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005256
5257 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005258 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005260 return final_branch_condition;
5261}
5262
5263
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005264void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
5265 Register temp = ToRegister(instr->TempAt(0));
5266 int true_block = chunk_->LookupDestination(instr->true_block_id());
5267 int false_block = chunk_->LookupDestination(instr->false_block_id());
5268
5269 EmitIsConstructCall(temp);
5270 EmitBranch(true_block, false_block, equal);
5271}
5272
5273
5274void LCodeGen::EmitIsConstructCall(Register temp) {
5275 // Get the frame pointer for the calling frame.
5276 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5277
5278 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005279 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005280 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5281 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005282 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005283 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5284
5285 // Check the marker in the calling frame.
5286 __ bind(&check_frame_marker);
5287 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5288 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5289}
5290
5291
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005292void LCodeGen::EnsureSpaceForLazyDeopt() {
5293 // Ensure that we have enough space after the previous lazy-bailout
5294 // instruction for patching the code here.
5295 int current_pc = masm()->pc_offset();
5296 int patch_size = Deoptimizer::patch_size();
5297 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5298 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005299 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005300 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005301 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005302}
5303
5304
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005305void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005306 EnsureSpaceForLazyDeopt();
5307 ASSERT(instr->HasEnvironment());
5308 LEnvironment* env = instr->environment();
5309 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5310 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005311}
5312
5313
5314void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5315 DeoptimizeIf(no_condition, instr->environment());
5316}
5317
5318
5319void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5320 LOperand* obj = instr->object();
5321 LOperand* key = instr->key();
5322 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005323 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005324 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005325 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005326 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005327 // Create safepoint generator that will also ensure enough space in the
5328 // reloc info for patching in deoptimization (since this is invoking a
5329 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005330 SafepointGenerator safepoint_generator(
5331 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005332 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005333 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005334}
5335
5336
ager@chromium.org04921a82011-06-27 13:21:41 +00005337void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005338 PushSafepointRegistersScope scope(this);
5339 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5340 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5341 RecordSafepointWithLazyDeopt(
5342 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5343 ASSERT(instr->HasEnvironment());
5344 LEnvironment* env = instr->environment();
5345 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005346}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005347
ager@chromium.org04921a82011-06-27 13:21:41 +00005348
5349void LCodeGen::DoStackCheck(LStackCheck* instr) {
5350 class DeferredStackCheck: public LDeferredCode {
5351 public:
5352 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5353 : LDeferredCode(codegen), instr_(instr) { }
5354 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005355 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005356 private:
5357 LStackCheck* instr_;
5358 };
5359
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005360 ASSERT(instr->HasEnvironment());
5361 LEnvironment* env = instr->environment();
5362 // There is no LLazyBailout instruction for stack-checks. We have to
5363 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005364 if (instr->hydrogen()->is_function_entry()) {
5365 // Perform stack overflow check.
5366 Label done;
5367 ExternalReference stack_limit =
5368 ExternalReference::address_of_stack_limit(isolate());
5369 __ cmp(esp, Operand::StaticVariable(stack_limit));
5370 __ j(above_equal, &done, Label::kNear);
5371
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005372 ASSERT(instr->context()->IsRegister());
5373 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00005374 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005375 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005376 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005377 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005378 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5379 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005380 } else {
5381 ASSERT(instr->hydrogen()->is_backwards_branch());
5382 // Perform stack overflow check if this goto needs it before jumping.
5383 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005384 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005385 ExternalReference stack_limit =
5386 ExternalReference::address_of_stack_limit(isolate());
5387 __ cmp(esp, Operand::StaticVariable(stack_limit));
5388 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005389 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005390 __ bind(instr->done_label());
5391 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005392 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5393 // Don't record a deoptimization index for the safepoint here.
5394 // This will be done explicitly when emitting call and the safepoint in
5395 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005396 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005397}
5398
5399
5400void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5401 // This is a pseudo-instruction that ensures that the environment here is
5402 // properly registered for deoptimization and records the assembler's PC
5403 // offset.
5404 LEnvironment* environment = instr->environment();
5405 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
5406 instr->SpilledDoubleRegisterArray());
5407
5408 // If the environment were already registered, we would have no way of
5409 // backpatching it with the spill slot operands.
5410 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005411 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005412 ASSERT(osr_pc_offset_ == -1);
5413 osr_pc_offset_ = masm()->pc_offset();
5414}
5415
5416
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005417void LCodeGen::DoIn(LIn* instr) {
5418 LOperand* obj = instr->object();
5419 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005420 EmitPushTaggedOperand(key);
5421 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005422 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005423 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005424 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005425 SafepointGenerator safepoint_generator(
5426 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005427 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005428}
5429
5430
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005431void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5432 __ cmp(eax, isolate()->factory()->undefined_value());
5433 DeoptimizeIf(equal, instr->environment());
5434
5435 __ cmp(eax, isolate()->factory()->null_value());
5436 DeoptimizeIf(equal, instr->environment());
5437
5438 __ test(eax, Immediate(kSmiTagMask));
5439 DeoptimizeIf(zero, instr->environment());
5440
5441 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5442 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5443 DeoptimizeIf(below_equal, instr->environment());
5444
5445 Label use_cache, call_runtime;
5446 __ CheckEnumCache(&call_runtime);
5447
5448 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5449 __ jmp(&use_cache, Label::kNear);
5450
5451 // Get the set of properties to enumerate.
5452 __ bind(&call_runtime);
5453 __ push(eax);
5454 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5455
5456 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5457 isolate()->factory()->meta_map());
5458 DeoptimizeIf(not_equal, instr->environment());
5459 __ bind(&use_cache);
5460}
5461
5462
5463void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5464 Register map = ToRegister(instr->map());
5465 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005466 Label load_cache, done;
5467 __ EnumLength(result, map);
5468 __ cmp(result, Immediate(Smi::FromInt(0)));
5469 __ j(not_equal, &load_cache);
5470 __ mov(result, isolate()->factory()->empty_fixed_array());
5471 __ jmp(&done);
5472
5473 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005474 __ LoadInstanceDescriptors(map, result);
5475 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005476 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005477 __ mov(result,
5478 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005479 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005480 __ test(result, result);
5481 DeoptimizeIf(equal, instr->environment());
5482}
5483
5484
5485void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5486 Register object = ToRegister(instr->value());
5487 __ cmp(ToRegister(instr->map()),
5488 FieldOperand(object, HeapObject::kMapOffset));
5489 DeoptimizeIf(not_equal, instr->environment());
5490}
5491
5492
5493void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5494 Register object = ToRegister(instr->object());
5495 Register index = ToRegister(instr->index());
5496
5497 Label out_of_object, done;
5498 __ cmp(index, Immediate(0));
5499 __ j(less, &out_of_object);
5500 __ mov(object, FieldOperand(object,
5501 index,
5502 times_half_pointer_size,
5503 JSObject::kHeaderSize));
5504 __ jmp(&done, Label::kNear);
5505
5506 __ bind(&out_of_object);
5507 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5508 __ neg(index);
5509 // Index is now equal to out of object property index plus 1.
5510 __ mov(object, FieldOperand(object,
5511 index,
5512 times_half_pointer_size,
5513 FixedArray::kHeaderSize - kPointerSize));
5514 __ bind(&done);
5515}
5516
5517
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005518#undef __
5519
5520} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005521
5522#endif // V8_TARGET_ARCH_IA32