blob: 5ef0739145f0a98b5299deddcbb28b352e2c3b3c [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.org471f2f12012-08-10 14:46:33 +0000426 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000427 ASSERT(translation_size == 2);
428 ASSERT(height == 0);
429 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000430 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000431 case ARGUMENTS_ADAPTOR:
432 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
433 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000434 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000435 for (int i = 0; i < translation_size; ++i) {
436 LOperand* value = environment->values()->at(i);
437 // spilled_registers_ and spilled_double_registers_ are either
438 // both NULL or both set.
439 if (environment->spilled_registers() != NULL && value != NULL) {
440 if (value->IsRegister() &&
441 environment->spilled_registers()[value->index()] != NULL) {
442 translation->MarkDuplicate();
443 AddToTranslation(translation,
444 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000445 environment->HasTaggedValueAt(i),
446 environment->HasUint32ValueAt(i));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000447 } else if (
448 value->IsDoubleRegister() &&
449 environment->spilled_double_registers()[value->index()] != NULL) {
450 translation->MarkDuplicate();
451 AddToTranslation(
452 translation,
453 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000454 false,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000455 false);
456 }
457 }
458
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000459 AddToTranslation(translation,
460 value,
461 environment->HasTaggedValueAt(i),
462 environment->HasUint32ValueAt(i));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000463 }
464}
465
466
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467void LCodeGen::AddToTranslation(Translation* translation,
468 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000469 bool is_tagged,
470 bool is_uint32) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000471 if (op == NULL) {
472 // TODO(twuerthinger): Introduce marker operands to indicate that this value
473 // is not present and must be reconstructed from the deoptimizer. Currently
474 // this is only used for the arguments object.
475 translation->StoreArgumentsObject();
476 } else if (op->IsStackSlot()) {
477 if (is_tagged) {
478 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000479 } else if (is_uint32) {
480 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000481 } else {
482 translation->StoreInt32StackSlot(op->index());
483 }
484 } else if (op->IsDoubleStackSlot()) {
485 translation->StoreDoubleStackSlot(op->index());
486 } else if (op->IsArgument()) {
487 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000488 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000489 translation->StoreStackSlot(src_index);
490 } else if (op->IsRegister()) {
491 Register reg = ToRegister(op);
492 if (is_tagged) {
493 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000494 } else if (is_uint32) {
495 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496 } else {
497 translation->StoreInt32Register(reg);
498 }
499 } else if (op->IsDoubleRegister()) {
500 XMMRegister reg = ToDoubleRegister(op);
501 translation->StoreDoubleRegister(reg);
502 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000503 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
504 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505 translation->StoreLiteral(src_index);
506 } else {
507 UNREACHABLE();
508 }
509}
510
511
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000512void LCodeGen::CallCodeGeneric(Handle<Code> code,
513 RelocInfo::Mode mode,
514 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000515 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000516 ASSERT(instr != NULL);
517 LPointerMap* pointers = instr->pointer_map();
518 RecordPosition(pointers->position());
519 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000520 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000521
522 // Signal that we don't inline smi code before these stubs in the
523 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000524 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000525 code->kind() == Code::COMPARE_IC) {
526 __ nop();
527 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528}
529
530
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000531void LCodeGen::CallCode(Handle<Code> code,
532 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000533 LInstruction* instr) {
534 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000535}
536
537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000539 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000540 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000541 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000542 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000543 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000544 RecordPosition(pointers->position());
545
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000546 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000547
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000548 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549}
550
551
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000552void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
553 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000554 LInstruction* instr,
555 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000556 if (context->IsRegister()) {
557 if (!ToRegister(context).is(esi)) {
558 __ mov(esi, ToRegister(context));
559 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000560 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000561 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000562 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000563 HConstant* constant =
564 chunk_->LookupConstant(LConstantOperand::cast(context));
565 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000566 } else {
567 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000568 }
569
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000570 __ CallRuntimeSaveDoubles(id);
571 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000572 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000573}
574
575
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000576void LCodeGen::RegisterEnvironmentForDeoptimization(
577 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000578 if (!environment->HasBeenRegistered()) {
579 // Physical stack frame layout:
580 // -x ............. -4 0 ..................................... y
581 // [incoming arguments] [spill slots] [pushed outgoing arguments]
582
583 // Layout of the environment:
584 // 0 ..................................................... size-1
585 // [parameters] [locals] [expression stack including arguments]
586
587 // Layout of the translation:
588 // 0 ........................................................ size - 1 + 4
589 // [expression stack including arguments] [locals] [4 words] [parameters]
590 // |>------------ translation_size ------------<|
591
592 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000593 int jsframe_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000594 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
595 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000596 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000597 ++jsframe_count;
598 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000600 Translation translation(&translations_, frame_count, jsframe_count,
601 zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000602 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000604 int pc_offset = masm()->pc_offset();
605 environment->Register(deoptimization_index,
606 translation.index(),
607 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000608 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 }
610}
611
612
613void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000614 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000615 ASSERT(environment->HasBeenRegistered());
616 int id = environment->deoptimization_index();
617 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000618 if (entry == NULL) {
619 Abort("bailout was not prepared");
620 return;
621 }
622
623 if (FLAG_deopt_every_n_times != 0) {
624 Handle<SharedFunctionInfo> shared(info_->shared_info());
625 Label no_deopt;
626 __ pushfd();
627 __ push(eax);
628 __ push(ebx);
629 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000630 __ mov(eax,
631 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000633 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634 if (FLAG_trap_on_deopt) __ int3();
635 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000636 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
637 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000638 __ pop(ebx);
639 __ pop(eax);
640 __ popfd();
641 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
642
643 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000644 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
645 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 __ pop(ebx);
647 __ pop(eax);
648 __ popfd();
649 }
650
651 if (cc == no_condition) {
652 if (FLAG_trap_on_deopt) __ int3();
653 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
654 } else {
655 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000656 Label done;
657 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000658 __ int3();
659 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
660 __ bind(&done);
661 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000662 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000663 }
664 }
665}
666
667
668void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
669 int length = deoptimizations_.length();
670 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000671 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000673
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000674 Handle<ByteArray> translations = translations_.CreateByteArray();
675 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000676 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
677
678 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000680 for (int i = 0; i < deoptimization_literals_.length(); i++) {
681 literals->set(i, *deoptimization_literals_[i]);
682 }
683 data->SetLiteralArray(*literals);
684
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000685 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000686 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
687
688 // Populate the deoptimization entries.
689 for (int i = 0; i < length; i++) {
690 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000691 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000692 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
693 data->SetArgumentsStackHeight(i,
694 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000695 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000696 }
697 code->set_deoptimization_data(*data);
698}
699
700
701int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
702 int result = deoptimization_literals_.length();
703 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
704 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
705 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000706 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000707 return result;
708}
709
710
711void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
712 ASSERT(deoptimization_literals_.length() == 0);
713
714 const ZoneList<Handle<JSFunction> >* inlined_closures =
715 chunk()->inlined_closures();
716
717 for (int i = 0, length = inlined_closures->length();
718 i < length;
719 i++) {
720 DefineDeoptimizationLiteral(inlined_closures->at(i));
721 }
722
723 inlined_function_count_ = deoptimization_literals_.length();
724}
725
726
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000727void LCodeGen::RecordSafepointWithLazyDeopt(
728 LInstruction* instr, SafepointMode safepoint_mode) {
729 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
730 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
731 } else {
732 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
733 RecordSafepointWithRegisters(
734 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
735 }
736}
737
738
ager@chromium.org378b34e2011-01-28 08:04:38 +0000739void LCodeGen::RecordSafepoint(
740 LPointerMap* pointers,
741 Safepoint::Kind kind,
742 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000743 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000744 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000745 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000746 Safepoint safepoint =
747 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000748 for (int i = 0; i < operands->length(); i++) {
749 LOperand* pointer = operands->at(i);
750 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000751 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000752 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000753 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000754 }
755 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000756}
757
758
759void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000760 Safepoint::DeoptMode mode) {
761 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000762}
763
764
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000765void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000766 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000767 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000768}
769
770
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000771void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
772 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000773 Safepoint::DeoptMode mode) {
774 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000775}
776
777
778void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000779 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000780 masm()->positions_recorder()->RecordPosition(position);
781}
782
783
784void LCodeGen::DoLabel(LLabel* label) {
785 if (label->is_loop_header()) {
786 Comment(";;; B%d - LOOP entry", label->block_id());
787 } else {
788 Comment(";;; B%d", label->block_id());
789 }
790 __ bind(label->label());
791 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000792 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793}
794
795
796void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000797 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000798}
799
800
801void LCodeGen::DoGap(LGap* gap) {
802 for (int i = LGap::FIRST_INNER_POSITION;
803 i <= LGap::LAST_INNER_POSITION;
804 i++) {
805 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
806 LParallelMove* move = gap->GetParallelMove(inner_pos);
807 if (move != NULL) DoParallelMove(move);
808 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000809}
810
811
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000812void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
813 DoGap(instr);
814}
815
816
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817void LCodeGen::DoParameter(LParameter* instr) {
818 // Nothing to do.
819}
820
821
822void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000823 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000824 ASSERT(ToRegister(instr->result()).is(eax));
825 switch (instr->hydrogen()->major_key()) {
826 case CodeStub::RegExpConstructResult: {
827 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000828 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829 break;
830 }
831 case CodeStub::RegExpExec: {
832 RegExpExecStub 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::SubString: {
837 SubStringStub 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 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000841 case CodeStub::NumberToString: {
842 NumberToStringStub 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 }
846 case CodeStub::StringAdd: {
847 StringAddStub stub(NO_STRING_ADD_FLAGS);
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::StringCompare: {
852 StringCompareStub stub;
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::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000857 TranscendentalCacheStub stub(instr->transcendental_type(),
858 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000859 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000860 break;
861 }
862 default:
863 UNREACHABLE();
864 }
865}
866
867
868void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
869 // Nothing to do.
870}
871
872
873void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000874 if (instr->hydrogen()->HasPowerOf2Divisor()) {
875 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000876
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000877 int32_t divisor =
878 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000879
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000880 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000881
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000882 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000883 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000884 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000885 __ neg(dividend);
886 __ and_(dividend, divisor - 1);
887 __ neg(dividend);
888 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000889 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000890 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000891 } else {
892 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000893 }
894 __ bind(&positive_dividend);
895 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000896 __ bind(&done);
897 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000898 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000899 Register left_reg = ToRegister(instr->InputAt(0));
900 Register right_reg = ToRegister(instr->InputAt(1));
901 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000902
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000903 ASSERT(left_reg.is(eax));
904 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000905 ASSERT(!right_reg.is(eax));
906 ASSERT(!right_reg.is(edx));
907
908 // Check for x % 0.
909 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000910 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000911 DeoptimizeIf(zero, instr->environment());
912 }
913
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000914 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000915 __ j(zero, &remainder_eq_dividend, Label::kNear);
916 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000917
918 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000919 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000920 // The sign of the divisor doesn't matter.
921 __ neg(right_reg);
922
923 __ bind(&both_positive);
924 // If the dividend is smaller than the nonnegative
925 // divisor, the dividend is the result.
926 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000927 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000928
929 // Check if the divisor is a PowerOfTwo integer.
930 Register scratch = ToRegister(instr->TempAt(0));
931 __ mov(scratch, right_reg);
932 __ sub(Operand(scratch), Immediate(1));
933 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000934 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000935 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000936 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000937
938 __ bind(&do_subtraction);
939 const int kUnfolds = 3;
940 // Try a few subtractions of the dividend.
941 __ mov(scratch, left_reg);
942 for (int i = 0; i < kUnfolds; i++) {
943 // Reduce the dividend by the divisor.
944 __ sub(left_reg, Operand(right_reg));
945 // Check if the dividend is less than the divisor.
946 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000947 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000948 }
949 __ mov(left_reg, scratch);
950
951 // Slow case, using idiv instruction.
952 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000953 // Sign extend to edx.
954 __ cdq();
955
956 // Check for (0 % -x) that will produce negative zero.
957 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000958 Label positive_left;
959 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000960 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000961 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000962 __ idiv(right_reg);
963
964 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000965 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000966 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000967
968 DeoptimizeIf(no_condition, instr->environment());
969 __ bind(&positive_left);
970 __ idiv(right_reg);
971 __ bind(&done);
972 } else {
973 __ idiv(right_reg);
974 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000975 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000976
977 __ bind(&remainder_eq_dividend);
978 __ mov(result_reg, left_reg);
979
980 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000981 }
982}
983
984
985void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000986 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000987 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000988 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
989 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
990 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000991
992 Register left_reg = eax;
993
994 // Check for x / 0.
995 Register right_reg = ToRegister(right);
996 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
997 __ test(right_reg, ToOperand(right));
998 DeoptimizeIf(zero, instr->environment());
999 }
1000
1001 // Check for (0 / -x) that will produce negative zero.
1002 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001003 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001004 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001005 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006 __ test(right_reg, ToOperand(right));
1007 DeoptimizeIf(sign, instr->environment());
1008 __ bind(&left_not_zero);
1009 }
1010
1011 // Check for (-kMinInt / -1).
1012 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001013 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001015 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016 __ cmp(right_reg, -1);
1017 DeoptimizeIf(zero, instr->environment());
1018 __ bind(&left_not_min_int);
1019 }
1020
1021 // Sign extend to edx.
1022 __ cdq();
1023 __ idiv(right_reg);
1024
1025 // Deoptimize if remainder is not 0.
1026 __ test(edx, Operand(edx));
1027 DeoptimizeIf(not_zero, instr->environment());
1028}
1029
1030
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001031void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1032 ASSERT(instr->InputAt(1)->IsConstantOperand());
1033
1034 Register dividend = ToRegister(instr->InputAt(0));
1035 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->InputAt(1)));
1036 Register result = ToRegister(instr->result());
1037
1038 switch (divisor) {
1039 case 0:
1040 DeoptimizeIf(no_condition, instr->environment());
1041 return;
1042
1043 case 1:
1044 __ Move(result, dividend);
1045 return;
1046
1047 case -1:
1048 __ Move(result, dividend);
1049 __ neg(result);
1050 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1051 DeoptimizeIf(zero, instr->environment());
1052 }
1053 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1054 DeoptimizeIf(overflow, instr->environment());
1055 }
1056 return;
1057 }
1058
1059 uint32_t divisor_abs = abs(divisor);
1060 if (IsPowerOf2(divisor_abs)) {
1061 int32_t power = WhichPowerOf2(divisor_abs);
1062 if (divisor < 0) {
1063 // Input[dividend] is clobbered.
1064 // The sequence is tedious because neg(dividend) might overflow.
1065 __ mov(result, dividend);
1066 __ sar(dividend, 31);
1067 __ neg(result);
1068 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1069 DeoptimizeIf(zero, instr->environment());
1070 }
1071 __ shl(dividend, 32 - power);
1072 __ sar(result, power);
1073 __ not_(dividend);
1074 // Clear result.sign if dividend.sign is set.
1075 __ and_(result, dividend);
1076 } else {
1077 __ Move(result, dividend);
1078 __ sar(result, power);
1079 }
1080 } else {
1081 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
1082 ASSERT(ToRegister(instr->result()).is(edx));
1083 Register scratch = ToRegister(instr->TempAt(0));
1084
1085 // Find b which: 2^b < divisor_abs < 2^(b+1).
1086 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1087 unsigned shift = 32 + b; // Precision +1bit (effectively).
1088 double multiplier_f =
1089 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1090 int64_t multiplier;
1091 if (multiplier_f - floor(multiplier_f) < 0.5) {
1092 multiplier = static_cast<int64_t>(floor(multiplier_f));
1093 } else {
1094 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1095 }
1096 // The multiplier is a uint32.
1097 ASSERT(multiplier > 0 &&
1098 multiplier < (static_cast<int64_t>(1) << 32));
1099 __ mov(scratch, dividend);
1100 if (divisor < 0 &&
1101 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1102 __ test(dividend, dividend);
1103 DeoptimizeIf(zero, instr->environment());
1104 }
1105 __ mov(edx, static_cast<int32_t>(multiplier));
1106 __ imul(edx);
1107 if (static_cast<int32_t>(multiplier) < 0) {
1108 __ add(edx, scratch);
1109 }
1110 Register reg_lo = eax;
1111 Register reg_byte_scratch = scratch;
1112 if (!reg_byte_scratch.is_byte_register()) {
1113 __ xchg(reg_lo, reg_byte_scratch);
1114 reg_lo = scratch;
1115 reg_byte_scratch = eax;
1116 }
1117 if (divisor < 0) {
1118 __ xor_(reg_byte_scratch, reg_byte_scratch);
1119 __ cmp(reg_lo, 0x40000000);
1120 __ setcc(above, reg_byte_scratch);
1121 __ neg(edx);
1122 __ sub(edx, reg_byte_scratch);
1123 } else {
1124 __ xor_(reg_byte_scratch, reg_byte_scratch);
1125 __ cmp(reg_lo, 0xC0000000);
1126 __ setcc(above_equal, reg_byte_scratch);
1127 __ add(edx, reg_byte_scratch);
1128 }
1129 __ sar(edx, shift - 32);
1130 }
1131}
1132
1133
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001134void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001135 Register left = ToRegister(instr->InputAt(0));
1136 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001137
1138 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001139 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001140 }
1141
1142 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001143 // Try strength reductions on the multiplication.
1144 // All replacement instructions are at most as long as the imul
1145 // and have better latency.
1146 int constant = ToInteger32(LConstantOperand::cast(right));
1147 if (constant == -1) {
1148 __ neg(left);
1149 } else if (constant == 0) {
1150 __ xor_(left, Operand(left));
1151 } else if (constant == 2) {
1152 __ add(left, Operand(left));
1153 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1154 // If we know that the multiplication can't overflow, it's safe to
1155 // use instructions that don't set the overflow flag for the
1156 // multiplication.
1157 switch (constant) {
1158 case 1:
1159 // Do nothing.
1160 break;
1161 case 3:
1162 __ lea(left, Operand(left, left, times_2, 0));
1163 break;
1164 case 4:
1165 __ shl(left, 2);
1166 break;
1167 case 5:
1168 __ lea(left, Operand(left, left, times_4, 0));
1169 break;
1170 case 8:
1171 __ shl(left, 3);
1172 break;
1173 case 9:
1174 __ lea(left, Operand(left, left, times_8, 0));
1175 break;
1176 case 16:
1177 __ shl(left, 4);
1178 break;
1179 default:
1180 __ imul(left, left, constant);
1181 break;
1182 }
1183 } else {
1184 __ imul(left, left, constant);
1185 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001186 } else {
1187 __ imul(left, ToOperand(right));
1188 }
1189
1190 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1191 DeoptimizeIf(overflow, instr->environment());
1192 }
1193
1194 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1195 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001196 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001197 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001198 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001199 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001200 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001201 DeoptimizeIf(no_condition, instr->environment());
1202 }
1203 } else {
1204 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001205 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001206 DeoptimizeIf(sign, instr->environment());
1207 }
1208 __ bind(&done);
1209 }
1210}
1211
1212
1213void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001214 LOperand* left = instr->InputAt(0);
1215 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001216 ASSERT(left->Equals(instr->result()));
1217 ASSERT(left->IsRegister());
1218
1219 if (right->IsConstantOperand()) {
1220 int right_operand = ToInteger32(LConstantOperand::cast(right));
1221 switch (instr->op()) {
1222 case Token::BIT_AND:
1223 __ and_(ToRegister(left), right_operand);
1224 break;
1225 case Token::BIT_OR:
1226 __ or_(ToRegister(left), right_operand);
1227 break;
1228 case Token::BIT_XOR:
1229 __ xor_(ToRegister(left), right_operand);
1230 break;
1231 default:
1232 UNREACHABLE();
1233 break;
1234 }
1235 } else {
1236 switch (instr->op()) {
1237 case Token::BIT_AND:
1238 __ and_(ToRegister(left), ToOperand(right));
1239 break;
1240 case Token::BIT_OR:
1241 __ or_(ToRegister(left), ToOperand(right));
1242 break;
1243 case Token::BIT_XOR:
1244 __ xor_(ToRegister(left), ToOperand(right));
1245 break;
1246 default:
1247 UNREACHABLE();
1248 break;
1249 }
1250 }
1251}
1252
1253
1254void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001255 LOperand* left = instr->InputAt(0);
1256 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001257 ASSERT(left->Equals(instr->result()));
1258 ASSERT(left->IsRegister());
1259 if (right->IsRegister()) {
1260 ASSERT(ToRegister(right).is(ecx));
1261
1262 switch (instr->op()) {
1263 case Token::SAR:
1264 __ sar_cl(ToRegister(left));
1265 break;
1266 case Token::SHR:
1267 __ shr_cl(ToRegister(left));
1268 if (instr->can_deopt()) {
1269 __ test(ToRegister(left), Immediate(0x80000000));
1270 DeoptimizeIf(not_zero, instr->environment());
1271 }
1272 break;
1273 case Token::SHL:
1274 __ shl_cl(ToRegister(left));
1275 break;
1276 default:
1277 UNREACHABLE();
1278 break;
1279 }
1280 } else {
1281 int value = ToInteger32(LConstantOperand::cast(right));
1282 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1283 switch (instr->op()) {
1284 case Token::SAR:
1285 if (shift_count != 0) {
1286 __ sar(ToRegister(left), shift_count);
1287 }
1288 break;
1289 case Token::SHR:
1290 if (shift_count == 0 && instr->can_deopt()) {
1291 __ test(ToRegister(left), Immediate(0x80000000));
1292 DeoptimizeIf(not_zero, instr->environment());
1293 } else {
1294 __ shr(ToRegister(left), shift_count);
1295 }
1296 break;
1297 case Token::SHL:
1298 if (shift_count != 0) {
1299 __ shl(ToRegister(left), shift_count);
1300 }
1301 break;
1302 default:
1303 UNREACHABLE();
1304 break;
1305 }
1306 }
1307}
1308
1309
1310void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001311 LOperand* left = instr->InputAt(0);
1312 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001313 ASSERT(left->Equals(instr->result()));
1314
1315 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001316 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001317 } else {
1318 __ sub(ToRegister(left), ToOperand(right));
1319 }
1320 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1321 DeoptimizeIf(overflow, instr->environment());
1322 }
1323}
1324
1325
1326void LCodeGen::DoConstantI(LConstantI* instr) {
1327 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001328 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001329}
1330
1331
1332void LCodeGen::DoConstantD(LConstantD* instr) {
1333 ASSERT(instr->result()->IsDoubleRegister());
1334 XMMRegister res = ToDoubleRegister(instr->result());
1335 double v = instr->value();
1336 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1337 // do so if the constant is -0.0.
1338 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001339 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001340 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001341 Register temp = ToRegister(instr->TempAt(0));
1342 uint64_t int_val = BitCast<uint64_t, double>(v);
1343 int32_t lower = static_cast<int32_t>(int_val);
1344 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001345 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001346 CpuFeatures::Scope scope(SSE4_1);
1347 if (lower != 0) {
1348 __ Set(temp, Immediate(lower));
1349 __ movd(res, Operand(temp));
1350 __ Set(temp, Immediate(upper));
1351 __ pinsrd(res, Operand(temp), 1);
1352 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001353 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001354 __ Set(temp, Immediate(upper));
1355 __ pinsrd(res, Operand(temp), 1);
1356 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001357 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001358 __ Set(temp, Immediate(upper));
1359 __ movd(res, Operand(temp));
1360 __ psllq(res, 32);
1361 if (lower != 0) {
1362 __ Set(temp, Immediate(lower));
1363 __ movd(xmm0, Operand(temp));
1364 __ por(res, xmm0);
1365 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001366 }
1367 }
1368}
1369
1370
1371void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001372 Register reg = ToRegister(instr->result());
1373 Handle<Object> handle = instr->value();
1374 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001375 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001376 } else {
1377 __ Set(reg, Immediate(handle));
1378 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001379}
1380
1381
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001382void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001383 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001384 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001385 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1386}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001387
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001389void LCodeGen::DoFixedArrayBaseLength(
1390 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001391 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001392 Register array = ToRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001393 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001394}
1395
1396
whesse@chromium.org7b260152011-06-20 15:33:18 +00001397void LCodeGen::DoElementsKind(LElementsKind* instr) {
1398 Register result = ToRegister(instr->result());
1399 Register input = ToRegister(instr->InputAt(0));
1400
1401 // Load map into |result|.
1402 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1403 // Load the map's "bit field 2" into |result|. We only need the first byte,
1404 // but the following masking takes care of that anyway.
1405 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1406 // Retrieve elements_kind from bit field 2.
1407 __ and_(result, Map::kElementsKindMask);
1408 __ shr(result, Map::kElementsKindShift);
1409}
1410
1411
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001412void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001413 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001414 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001415 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001416 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001417
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001418 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001420 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001421
1422 // If the object is not a value type, return the object.
1423 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001424 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001425 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1426
1427 __ bind(&done);
1428}
1429
1430
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001431void LCodeGen::DoDateField(LDateField* instr) {
1432 Register object = ToRegister(instr->InputAt(0));
1433 Register result = ToRegister(instr->result());
1434 Register scratch = ToRegister(instr->TempAt(0));
1435 Smi* index = instr->index();
1436 Label runtime, done;
1437 ASSERT(object.is(result));
1438 ASSERT(object.is(eax));
1439
1440#ifdef DEBUG
1441 __ AbortIfSmi(object);
1442 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
1443 __ Assert(equal, "Trying to get date field from non-date.");
1444#endif
1445
1446 if (index->value() == 0) {
1447 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1448 } else {
1449 if (index->value() < JSDate::kFirstUncachedField) {
1450 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1451 __ mov(scratch, Operand::StaticVariable(stamp));
1452 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1453 __ j(not_equal, &runtime, Label::kNear);
1454 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1455 kPointerSize * index->value()));
1456 __ jmp(&done);
1457 }
1458 __ bind(&runtime);
1459 __ PrepareCallCFunction(2, scratch);
1460 __ mov(Operand(esp, 0), object);
1461 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1462 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1463 __ bind(&done);
1464 }
1465}
1466
1467
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001468void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001469 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001470 ASSERT(input->Equals(instr->result()));
1471 __ not_(ToRegister(input));
1472}
1473
1474
1475void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001476 __ push(ToOperand(instr->value()));
1477 ASSERT(ToRegister(instr->context()).is(esi));
1478 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479
1480 if (FLAG_debug_code) {
1481 Comment("Unreachable code.");
1482 __ int3();
1483 }
1484}
1485
1486
1487void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001488 LOperand* left = instr->InputAt(0);
1489 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001490 ASSERT(left->Equals(instr->result()));
1491
1492 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001493 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001494 } else {
1495 __ add(ToRegister(left), ToOperand(right));
1496 }
1497
1498 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1499 DeoptimizeIf(overflow, instr->environment());
1500 }
1501}
1502
1503
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001504void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
1505 LOperand* left = instr->InputAt(0);
1506 LOperand* right = instr->InputAt(1);
1507 ASSERT(left->Equals(instr->result()));
1508 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1509 if (instr->hydrogen()->representation().IsInteger32()) {
1510 Label return_left;
1511 Condition condition = (operation == HMathMinMax::kMathMin)
1512 ? less_equal
1513 : greater_equal;
1514 if (right->IsConstantOperand()) {
1515 Operand left_op = ToOperand(left);
1516 Immediate right_imm = ToInteger32Immediate(right);
1517 __ cmp(left_op, right_imm);
1518 __ j(condition, &return_left, Label::kNear);
1519 __ mov(left_op, right_imm);
1520 } else {
1521 Register left_reg = ToRegister(left);
1522 Operand right_op = ToOperand(right);
1523 __ cmp(left_reg, right_op);
1524 __ j(condition, &return_left, Label::kNear);
1525 __ mov(left_reg, right_op);
1526 }
1527 __ bind(&return_left);
1528 } else {
1529 ASSERT(instr->hydrogen()->representation().IsDouble());
1530 Label check_nan_left, check_zero, return_left, return_right;
1531 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1532 XMMRegister left_reg = ToDoubleRegister(left);
1533 XMMRegister right_reg = ToDoubleRegister(right);
1534 __ ucomisd(left_reg, right_reg);
1535 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1536 __ j(equal, &check_zero, Label::kNear); // left == right.
1537 __ j(condition, &return_left, Label::kNear);
1538 __ jmp(&return_right, Label::kNear);
1539
1540 __ bind(&check_zero);
1541 XMMRegister xmm_scratch = xmm0;
1542 __ xorps(xmm_scratch, xmm_scratch);
1543 __ ucomisd(left_reg, xmm_scratch);
1544 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1545 // At this point, both left and right are either 0 or -0.
1546 if (operation == HMathMinMax::kMathMin) {
1547 __ orpd(left_reg, right_reg);
1548 } else {
1549 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1550 __ addsd(left_reg, right_reg);
1551 }
1552 __ jmp(&return_left, Label::kNear);
1553
1554 __ bind(&check_nan_left);
1555 __ ucomisd(left_reg, left_reg); // NaN check.
1556 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1557 __ bind(&return_right);
1558 __ movsd(left_reg, right_reg);
1559
1560 __ bind(&return_left);
1561 }
1562}
1563
1564
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001565void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001566 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1567 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1568 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001569 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001570 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001571 switch (instr->op()) {
1572 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001573 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001574 break;
1575 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001576 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001577 break;
1578 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001579 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580 break;
1581 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001582 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 break;
1584 case Token::MOD: {
1585 // Pass two doubles as arguments on the stack.
1586 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001587 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1588 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 __ CallCFunction(
1590 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1591 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001592
1593 // Return value is in st(0) on ia32.
1594 // Store it into the (fixed) result register.
1595 __ sub(Operand(esp), Immediate(kDoubleSize));
1596 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001597 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001598 __ add(Operand(esp), Immediate(kDoubleSize));
1599 break;
1600 }
1601 default:
1602 UNREACHABLE();
1603 break;
1604 }
1605}
1606
1607
1608void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001609 ASSERT(ToRegister(instr->context()).is(esi));
1610 ASSERT(ToRegister(instr->left()).is(edx));
1611 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001612 ASSERT(ToRegister(instr->result()).is(eax));
1613
danno@chromium.org40cb8782011-05-25 07:58:50 +00001614 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001615 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001616 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617}
1618
1619
1620int LCodeGen::GetNextEmittedBlock(int block) {
1621 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1622 LLabel* label = chunk_->GetLabel(i);
1623 if (!label->HasReplacement()) return i;
1624 }
1625 return -1;
1626}
1627
1628
1629void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1630 int next_block = GetNextEmittedBlock(current_block_);
1631 right_block = chunk_->LookupDestination(right_block);
1632 left_block = chunk_->LookupDestination(left_block);
1633
1634 if (right_block == left_block) {
1635 EmitGoto(left_block);
1636 } else if (left_block == next_block) {
1637 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1638 } else if (right_block == next_block) {
1639 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1640 } else {
1641 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1642 __ jmp(chunk_->GetAssemblyLabel(right_block));
1643 }
1644}
1645
1646
1647void LCodeGen::DoBranch(LBranch* instr) {
1648 int true_block = chunk_->LookupDestination(instr->true_block_id());
1649 int false_block = chunk_->LookupDestination(instr->false_block_id());
1650
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001651 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001653 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001654 __ test(reg, Operand(reg));
1655 EmitBranch(true_block, false_block, not_zero);
1656 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001657 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001658 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001659 __ ucomisd(reg, xmm0);
1660 EmitBranch(true_block, false_block, not_equal);
1661 } else {
1662 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001663 Register reg = ToRegister(instr->InputAt(0));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001664 HType type = instr->hydrogen()->value()->type();
1665 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001667 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001668 } else if (type.IsSmi()) {
1669 __ test(reg, Operand(reg));
1670 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001671 } else {
1672 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1673 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1674
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001675 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1676 // Avoid deopts in the case where we've never executed this path before.
1677 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001679 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1680 // undefined -> false.
1681 __ cmp(reg, factory()->undefined_value());
1682 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001683 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001684 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1685 // true -> true.
1686 __ cmp(reg, factory()->true_value());
1687 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001688 // false -> false.
1689 __ cmp(reg, factory()->false_value());
1690 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001691 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001692 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1693 // 'null' -> false.
1694 __ cmp(reg, factory()->null_value());
1695 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001696 }
1697
1698 if (expected.Contains(ToBooleanStub::SMI)) {
1699 // Smis: 0 -> false, all other -> true.
1700 __ test(reg, Operand(reg));
1701 __ j(equal, false_label);
1702 __ JumpIfSmi(reg, true_label);
1703 } else if (expected.NeedsMap()) {
1704 // If we need a map later and have a Smi -> deopt.
1705 __ test(reg, Immediate(kSmiTagMask));
1706 DeoptimizeIf(zero, instr->environment());
1707 }
1708
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001709 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001710 if (expected.NeedsMap()) {
1711 map = ToRegister(instr->TempAt(0));
1712 ASSERT(!map.is(reg));
1713 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001714
1715 if (expected.CanBeUndetectable()) {
1716 // Undetectable -> false.
1717 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1718 1 << Map::kIsUndetectable);
1719 __ j(not_zero, false_label);
1720 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001721 }
1722
1723 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1724 // spec object -> true.
1725 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1726 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001727 }
1728
1729 if (expected.Contains(ToBooleanStub::STRING)) {
1730 // String value -> false iff empty.
1731 Label not_string;
1732 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1733 __ j(above_equal, &not_string, Label::kNear);
1734 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1735 __ j(not_zero, true_label);
1736 __ jmp(false_label);
1737 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001738 }
1739
1740 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1741 // heap number -> false iff +0, -0, or NaN.
1742 Label not_heap_number;
1743 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1744 factory()->heap_number_map());
1745 __ j(not_equal, &not_heap_number, Label::kNear);
1746 __ fldz();
1747 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1748 __ FCmp();
1749 __ j(zero, false_label);
1750 __ jmp(true_label);
1751 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001752 }
1753
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001754 // We've seen something for the first time -> deopt.
1755 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 }
1757 }
1758}
1759
1760
ager@chromium.org04921a82011-06-27 13:21:41 +00001761void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001762 block = chunk_->LookupDestination(block);
1763 int next_block = GetNextEmittedBlock(current_block_);
1764 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001765 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001766 }
1767}
1768
1769
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001770void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001771 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001772}
1773
1774
1775Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1776 Condition cond = no_condition;
1777 switch (op) {
1778 case Token::EQ:
1779 case Token::EQ_STRICT:
1780 cond = equal;
1781 break;
1782 case Token::LT:
1783 cond = is_unsigned ? below : less;
1784 break;
1785 case Token::GT:
1786 cond = is_unsigned ? above : greater;
1787 break;
1788 case Token::LTE:
1789 cond = is_unsigned ? below_equal : less_equal;
1790 break;
1791 case Token::GTE:
1792 cond = is_unsigned ? above_equal : greater_equal;
1793 break;
1794 case Token::IN:
1795 case Token::INSTANCEOF:
1796 default:
1797 UNREACHABLE();
1798 }
1799 return cond;
1800}
1801
1802
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001803void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001804 LOperand* left = instr->InputAt(0);
1805 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001806 int false_block = chunk_->LookupDestination(instr->false_block_id());
1807 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001808 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001809
1810 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1811 // We can statically evaluate the comparison.
1812 double left_val = ToDouble(LConstantOperand::cast(left));
1813 double right_val = ToDouble(LConstantOperand::cast(right));
1814 int next_block =
1815 EvalComparison(instr->op(), left_val, right_val) ? true_block
1816 : false_block;
1817 EmitGoto(next_block);
1818 } else {
1819 if (instr->is_double()) {
1820 // Don't base result on EFLAGS when a NaN is involved. Instead
1821 // jump to the false block.
1822 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1823 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1824 } else {
1825 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001826 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001827 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001828 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001829 // We transposed the operands. Reverse the condition.
1830 cc = ReverseCondition(cc);
1831 } else {
1832 __ cmp(ToRegister(left), ToOperand(right));
1833 }
1834 }
1835 EmitBranch(true_block, false_block, cc);
1836 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001837}
1838
1839
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001840void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001841 Register left = ToRegister(instr->InputAt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001842 Operand right = ToOperand(instr->InputAt(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001843 int false_block = chunk_->LookupDestination(instr->false_block_id());
1844 int true_block = chunk_->LookupDestination(instr->true_block_id());
1845
1846 __ cmp(left, Operand(right));
1847 EmitBranch(true_block, false_block, equal);
1848}
1849
1850
whesse@chromium.org7b260152011-06-20 15:33:18 +00001851void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
1852 Register left = ToRegister(instr->InputAt(0));
1853 int true_block = chunk_->LookupDestination(instr->true_block_id());
1854 int false_block = chunk_->LookupDestination(instr->false_block_id());
1855
1856 __ cmp(left, instr->hydrogen()->right());
1857 EmitBranch(true_block, false_block, equal);
1858}
1859
1860
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001861void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001862 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863 int false_block = chunk_->LookupDestination(instr->false_block_id());
1864
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001865 // If the expression is known to be untagged or a smi, then it's definitely
1866 // not null, and it can't be a an undetectable object.
1867 if (instr->hydrogen()->representation().IsSpecialization() ||
1868 instr->hydrogen()->type().IsSmi()) {
1869 EmitGoto(false_block);
1870 return;
1871 }
1872
1873 int true_block = chunk_->LookupDestination(instr->true_block_id());
1874 Handle<Object> nil_value = instr->nil() == kNullValue ?
1875 factory()->null_value() :
1876 factory()->undefined_value();
1877 __ cmp(reg, nil_value);
1878 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001879 EmitBranch(true_block, false_block, equal);
1880 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001881 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
1882 factory()->undefined_value() :
1883 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001884 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1885 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1886 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001887 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001888 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001889 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 // Check for undetectable objects by looking in the bit field in
1891 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001892 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001893 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1894 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1895 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1896 EmitBranch(true_block, false_block, not_zero);
1897 }
1898}
1899
1900
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001901Condition LCodeGen::EmitIsObject(Register input,
1902 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001903 Label* is_not_object,
1904 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001905 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001908 __ j(equal, is_object);
1909
1910 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1911 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001912 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
1913 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001914 __ j(not_zero, is_not_object);
1915
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001916 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
1917 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001918 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001919 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001920 return below_equal;
1921}
1922
1923
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001924void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001925 Register reg = ToRegister(instr->InputAt(0));
1926 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001927
1928 int true_block = chunk_->LookupDestination(instr->true_block_id());
1929 int false_block = chunk_->LookupDestination(instr->false_block_id());
1930 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1931 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1932
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001933 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001934
1935 EmitBranch(true_block, false_block, true_cond);
1936}
1937
1938
erikcorry0ad885c2011-11-21 13:51:57 +00001939Condition LCodeGen::EmitIsString(Register input,
1940 Register temp1,
1941 Label* is_not_string) {
1942 __ JumpIfSmi(input, is_not_string);
1943
1944 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
1945
1946 return cond;
1947}
1948
1949
1950void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
1951 Register reg = ToRegister(instr->InputAt(0));
1952 Register temp = ToRegister(instr->TempAt(0));
1953
1954 int true_block = chunk_->LookupDestination(instr->true_block_id());
1955 int false_block = chunk_->LookupDestination(instr->false_block_id());
1956 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1957
1958 Condition true_cond = EmitIsString(reg, temp, false_label);
1959
1960 EmitBranch(true_block, false_block, true_cond);
1961}
1962
1963
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001964void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001965 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001966
1967 int true_block = chunk_->LookupDestination(instr->true_block_id());
1968 int false_block = chunk_->LookupDestination(instr->false_block_id());
1969
1970 __ test(input, Immediate(kSmiTagMask));
1971 EmitBranch(true_block, false_block, zero);
1972}
1973
1974
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001975void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1976 Register input = ToRegister(instr->InputAt(0));
1977 Register temp = ToRegister(instr->TempAt(0));
1978
1979 int true_block = chunk_->LookupDestination(instr->true_block_id());
1980 int false_block = chunk_->LookupDestination(instr->false_block_id());
1981
1982 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001983 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001984 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1985 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1986 1 << Map::kIsUndetectable);
1987 EmitBranch(true_block, false_block, not_zero);
1988}
1989
1990
erikcorry0ad885c2011-11-21 13:51:57 +00001991static Condition ComputeCompareCondition(Token::Value op) {
1992 switch (op) {
1993 case Token::EQ_STRICT:
1994 case Token::EQ:
1995 return equal;
1996 case Token::LT:
1997 return less;
1998 case Token::GT:
1999 return greater;
2000 case Token::LTE:
2001 return less_equal;
2002 case Token::GTE:
2003 return greater_equal;
2004 default:
2005 UNREACHABLE();
2006 return no_condition;
2007 }
2008}
2009
2010
2011void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2012 Token::Value op = instr->op();
2013 int true_block = chunk_->LookupDestination(instr->true_block_id());
2014 int false_block = chunk_->LookupDestination(instr->false_block_id());
2015
2016 Handle<Code> ic = CompareIC::GetUninitialized(op);
2017 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2018
2019 Condition condition = ComputeCompareCondition(op);
2020 __ test(eax, Operand(eax));
2021
2022 EmitBranch(true_block, false_block, condition);
2023}
2024
2025
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002026static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002027 InstanceType from = instr->from();
2028 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002029 if (from == FIRST_TYPE) return to;
2030 ASSERT(from == to || to == LAST_TYPE);
2031 return from;
2032}
2033
2034
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002035static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002036 InstanceType from = instr->from();
2037 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002038 if (from == to) return equal;
2039 if (to == LAST_TYPE) return above_equal;
2040 if (from == FIRST_TYPE) return below_equal;
2041 UNREACHABLE();
2042 return equal;
2043}
2044
2045
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002046void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002047 Register input = ToRegister(instr->InputAt(0));
2048 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002049
2050 int true_block = chunk_->LookupDestination(instr->true_block_id());
2051 int false_block = chunk_->LookupDestination(instr->false_block_id());
2052
2053 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2054
whesse@chromium.org7b260152011-06-20 15:33:18 +00002055 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002056
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002057 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2058 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059}
2060
2061
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002062void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
2063 Register input = ToRegister(instr->InputAt(0));
2064 Register result = ToRegister(instr->result());
2065
2066 if (FLAG_debug_code) {
2067 __ AbortIfNotString(input);
2068 }
2069
2070 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2071 __ IndexFromHash(result, result);
2072}
2073
2074
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002075void LCodeGen::DoHasCachedArrayIndexAndBranch(
2076 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002077 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002078
2079 int true_block = chunk_->LookupDestination(instr->true_block_id());
2080 int false_block = chunk_->LookupDestination(instr->false_block_id());
2081
2082 __ test(FieldOperand(input, String::kHashFieldOffset),
2083 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002084 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002085}
2086
2087
2088// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002089// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002090void LCodeGen::EmitClassOfTest(Label* is_true,
2091 Label* is_false,
2092 Handle<String>class_name,
2093 Register input,
2094 Register temp,
2095 Register temp2) {
2096 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002097 ASSERT(!input.is(temp2));
2098 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002099 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002100
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002101 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002102 // Assuming the following assertions, we can use the same compares to test
2103 // for both being a function type and being in the object type range.
2104 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2105 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2106 FIRST_SPEC_OBJECT_TYPE + 1);
2107 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2108 LAST_SPEC_OBJECT_TYPE - 1);
2109 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2110 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2111 __ j(below, is_false);
2112 __ j(equal, is_true);
2113 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2114 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002115 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002116 // Faster code path to avoid two compares: subtract lower bound from the
2117 // actual type and do a signed compare with the width of the type range.
2118 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002119 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002121 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2122 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002123 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002124 }
2125
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002126 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002127 // Check if the constructor in the map is a function.
2128 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002129 // Objects with a non-function constructor have class 'Object'.
2130 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
2131 if (class_name->IsEqualTo(CStrVector("Object"))) {
2132 __ j(not_equal, is_true);
2133 } else {
2134 __ j(not_equal, is_false);
2135 }
2136
2137 // temp now contains the constructor function. Grab the
2138 // instance class name from there.
2139 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2140 __ mov(temp, FieldOperand(temp,
2141 SharedFunctionInfo::kInstanceClassNameOffset));
2142 // The class name we are testing against is a symbol because it's a literal.
2143 // The name in the constructor is a symbol because of the way the context is
2144 // booted. This routine isn't expected to work for random API-created
2145 // classes and it doesn't have to because you can't access it with natives
2146 // syntax. Since both sides are symbols it is sufficient to use an identity
2147 // comparison.
2148 __ cmp(temp, class_name);
2149 // End with the answer in the z flag.
2150}
2151
2152
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002153void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002154 Register input = ToRegister(instr->InputAt(0));
2155 Register temp = ToRegister(instr->TempAt(0));
2156 Register temp2 = ToRegister(instr->TempAt(1));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002157
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002158 Handle<String> class_name = instr->hydrogen()->class_name();
2159
2160 int true_block = chunk_->LookupDestination(instr->true_block_id());
2161 int false_block = chunk_->LookupDestination(instr->false_block_id());
2162
2163 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2164 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2165
2166 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2167
2168 EmitBranch(true_block, false_block, equal);
2169}
2170
2171
2172void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002173 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002174 int true_block = instr->true_block_id();
2175 int false_block = instr->false_block_id();
2176
2177 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2178 EmitBranch(true_block, false_block, equal);
2179}
2180
2181
2182void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002183 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002184 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002185 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002186 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002187
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002188 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002189 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002190 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002192 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002193 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002195 __ bind(&done);
2196}
2197
2198
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002199void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2200 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2201 public:
2202 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2203 LInstanceOfKnownGlobal* instr)
2204 : LDeferredCode(codegen), instr_(instr) { }
2205 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002206 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002207 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002208 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002209 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002210 private:
2211 LInstanceOfKnownGlobal* instr_;
2212 Label map_check_;
2213 };
2214
2215 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002216 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002217
2218 Label done, false_result;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002219 Register object = ToRegister(instr->InputAt(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002220 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002221
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002222 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002223 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002224
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002225 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002226 // hole value will be patched to the last map/result pair generated by the
2227 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002228 Label cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002229 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002230 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2231 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002232 Handle<JSGlobalPropertyCell> cache_cell =
2233 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2234 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002235 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002237 __ jmp(&done);
2238
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002239 // The inlined call site cache did not match. Check for null and string
2240 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002241 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002242 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002244 __ j(equal, &false_result);
2245
2246 // String values are not instances of anything.
2247 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2248 __ j(is_string, &false_result);
2249
2250 // Go to the deferred code.
2251 __ jmp(deferred->entry());
2252
2253 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002255
2256 // Here result has either true or false. Deferred code also produces true or
2257 // false object.
2258 __ bind(deferred->exit());
2259 __ bind(&done);
2260}
2261
2262
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002263void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2264 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002265 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002266
2267 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2268 flags = static_cast<InstanceofStub::Flags>(
2269 flags | InstanceofStub::kArgsInRegisters);
2270 flags = static_cast<InstanceofStub::Flags>(
2271 flags | InstanceofStub::kCallSiteInlineCheck);
2272 flags = static_cast<InstanceofStub::Flags>(
2273 flags | InstanceofStub::kReturnTrueFalseObject);
2274 InstanceofStub stub(flags);
2275
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002276 // Get the temp register reserved by the instruction. This needs to be a
2277 // register which is pushed last by PushSafepointRegisters as top of the
2278 // stack is used to pass the offset to the location of the map check to
2279 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002280 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002281 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002282 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002283 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002284 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002285 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002286 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002287 CallCodeGeneric(stub.GetCode(),
2288 RelocInfo::CODE_TARGET,
2289 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002290 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002291 // Get the deoptimization index of the LLazyBailout-environment that
2292 // corresponds to this instruction.
2293 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002294 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2295
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002296 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002297 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002298}
2299
2300
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002301void LCodeGen::DoCmpT(LCmpT* instr) {
2302 Token::Value op = instr->op();
2303
2304 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002305 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002306
2307 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002308 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002309 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002310 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002311 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002312 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002313 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002314 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002315 __ bind(&done);
2316}
2317
2318
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002319void LCodeGen::DoReturn(LReturn* instr) {
2320 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002321 // Preserve the return value on the stack and rely on the runtime call
2322 // to return the value in the same register. We're leaving the code
2323 // managed by the register allocator and tearing down the frame, it's
2324 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002325 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002326 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002327 __ CallRuntime(Runtime::kTraceExit, 1);
2328 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002329 if (dynamic_frame_alignment_) {
2330 // Fetch the state of the dynamic frame alignment.
2331 __ mov(edx, Operand(ebp,
2332 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2333 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334 __ mov(esp, ebp);
2335 __ pop(ebp);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002336 if (dynamic_frame_alignment_) {
2337 Label no_padding;
2338 __ cmp(edx, Immediate(kNoAlignmentPadding));
2339 __ j(equal, &no_padding);
2340 if (FLAG_debug_code) {
2341 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2342 Immediate(kAlignmentZapValue));
2343 __ Assert(equal, "expected alignment marker");
2344 }
2345 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2346 __ bind(&no_padding);
2347 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00002348 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002349}
2350
2351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002352void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002353 Register result = ToRegister(instr->result());
2354 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002356 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002357 DeoptimizeIf(equal, instr->environment());
2358 }
2359}
2360
2361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002362void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2363 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002364 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002365 ASSERT(ToRegister(instr->result()).is(eax));
2366
2367 __ mov(ecx, instr->name());
2368 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2369 RelocInfo::CODE_TARGET_CONTEXT;
2370 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002371 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002372}
2373
2374
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002375void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002376 Register value = ToRegister(instr->value());
2377 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002378
2379 // If the cell we are storing to contains the hole it could have
2380 // been deleted from the property dictionary. In that case, we need
2381 // to update the property details in the property dictionary to mark
2382 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002383 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002384 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002385 DeoptimizeIf(equal, instr->environment());
2386 }
2387
2388 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002389 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002390 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002391}
2392
2393
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002394void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2395 ASSERT(ToRegister(instr->context()).is(esi));
2396 ASSERT(ToRegister(instr->global_object()).is(edx));
2397 ASSERT(ToRegister(instr->value()).is(eax));
2398
2399 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002400 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002401 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2402 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002403 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002404}
2405
2406
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002407void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002408 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002409 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002410 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002411
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002412 if (instr->hydrogen()->RequiresHoleCheck()) {
2413 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002414 if (instr->hydrogen()->DeoptimizesOnHole()) {
2415 DeoptimizeIf(equal, instr->environment());
2416 } else {
2417 Label is_not_hole;
2418 __ j(not_equal, &is_not_hole, Label::kNear);
2419 __ mov(result, factory()->undefined_value());
2420 __ bind(&is_not_hole);
2421 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002422 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002423}
2424
2425
2426void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2427 Register context = ToRegister(instr->context());
2428 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002429
2430 Label skip_assignment;
2431
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002432 Operand target = ContextOperand(context, instr->slot_index());
2433 if (instr->hydrogen()->RequiresHoleCheck()) {
2434 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002435 if (instr->hydrogen()->DeoptimizesOnHole()) {
2436 DeoptimizeIf(equal, instr->environment());
2437 } else {
2438 __ j(not_equal, &skip_assignment, Label::kNear);
2439 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002440 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002441
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002442 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002443 if (instr->hydrogen()->NeedsWriteBarrier()) {
2444 HType type = instr->hydrogen()->value()->type();
2445 SmiCheck check_needed =
2446 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002447 Register temp = ToRegister(instr->TempAt(0));
2448 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002449 __ RecordWriteContextSlot(context,
2450 offset,
2451 value,
2452 temp,
2453 kSaveFPRegs,
2454 EMIT_REMEMBERED_SET,
2455 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002456 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002457
2458 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002459}
2460
2461
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002462void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002463 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002464 Register result = ToRegister(instr->result());
2465 if (instr->hydrogen()->is_in_object()) {
2466 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2467 } else {
2468 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2469 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2470 }
2471}
2472
2473
lrn@chromium.org1c092762011-05-09 09:42:16 +00002474void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2475 Register object,
2476 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002477 Handle<String> name,
2478 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002479 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002480 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002481 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002482 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002483 int index = lookup.GetLocalFieldIndexFromMap(*type);
2484 int offset = index * kPointerSize;
2485 if (index < 0) {
2486 // Negative property indices are in-object properties, indexed
2487 // from the end of the fixed part of the object.
2488 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2489 } else {
2490 // Non-negative property indices are in the properties array.
2491 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2492 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2493 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002494 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002495 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002496 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002497 } else {
2498 // Negative lookup.
2499 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002500 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002501 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002502 while (*current != heap->null_value()) {
2503 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002504 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002505 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002506 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002507 current =
2508 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002509 }
2510 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002511 }
2512}
2513
2514
2515void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2516 ASSERT(!operand->IsDoubleRegister());
2517 if (operand->IsConstantOperand()) {
2518 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2519 if (object->IsSmi()) {
2520 __ Push(Handle<Smi>::cast(object));
2521 } else {
2522 __ PushHeapObject(Handle<HeapObject>::cast(object));
2523 }
2524 } else if (operand->IsRegister()) {
2525 __ push(ToRegister(operand));
2526 } else {
2527 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002528 }
2529}
2530
2531
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002532// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2533// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002534static bool CompactEmit(SmallMapList* list,
2535 Handle<String> name,
2536 int i,
2537 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002538 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002539 // If the map has ElementsKind transitions, we will generate map checks
2540 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002541 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002542 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002543 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002544 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002545}
2546
2547
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002548void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2549 Register object = ToRegister(instr->object());
2550 Register result = ToRegister(instr->result());
2551
2552 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002553 bool need_generic = instr->hydrogen()->need_generic();
2554
2555 if (map_count == 0 && !need_generic) {
2556 DeoptimizeIf(no_condition, instr->environment());
2557 return;
2558 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002559 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002560 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002561 bool all_are_compact = true;
2562 for (int i = 0; i < map_count; ++i) {
2563 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2564 all_are_compact = false;
2565 break;
2566 }
2567 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002568 for (int i = 0; i < map_count; ++i) {
2569 bool last = (i == map_count - 1);
2570 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002571 Label check_passed;
2572 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002573 if (last && !need_generic) {
2574 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002575 __ bind(&check_passed);
2576 EmitLoadFieldOrConstantFunction(
2577 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002578 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002579 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002580 bool compact = all_are_compact ? true :
2581 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
2582 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
2583 __ bind(&check_passed);
2584 EmitLoadFieldOrConstantFunction(
2585 result, object, map, name, instr->environment());
2586 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002587 __ bind(&next);
2588 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002589 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002590 if (need_generic) {
2591 __ mov(ecx, name);
2592 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2593 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2594 }
2595 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002596}
2597
2598
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002599void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002600 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002601 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002602 ASSERT(ToRegister(instr->result()).is(eax));
2603
2604 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002605 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002606 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002607}
2608
2609
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002610void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2611 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002612 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002613 Register result = ToRegister(instr->result());
2614
2615 // Check that the function really is a function.
2616 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2617 DeoptimizeIf(not_equal, instr->environment());
2618
2619 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002620 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002621 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2622 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002623 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002624
2625 // Get the prototype or initial map from the function.
2626 __ mov(result,
2627 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2628
2629 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002631 DeoptimizeIf(equal, instr->environment());
2632
2633 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002634 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002635 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002636 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002637
2638 // Get the prototype from the initial map.
2639 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002640 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002641
2642 // Non-instance prototype: Fetch prototype from constructor field
2643 // in the function's map.
2644 __ bind(&non_instance);
2645 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2646
2647 // All done.
2648 __ bind(&done);
2649}
2650
2651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002652void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002653 Register result = ToRegister(instr->result());
2654 Register input = ToRegister(instr->InputAt(0));
2655 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002656 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002657 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002658 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002659 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002660 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002661 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002662 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002663 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002664 Register temp((result.is(eax)) ? ebx : eax);
2665 __ push(temp);
2666 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002667 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2668 __ and_(temp, Map::kElementsKindMask);
2669 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002670 __ cmp(temp, GetInitialFastElementsKind());
2671 __ j(less, &fail, Label::kNear);
2672 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
2673 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002674 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002675 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002676 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002677 __ j(less_equal, &ok, Label::kNear);
2678 __ bind(&fail);
2679 __ Abort("Check for fast or external elements failed.");
2680 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002681 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002682 __ bind(&done);
2683 }
2684}
2685
2686
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002687void LCodeGen::DoLoadExternalArrayPointer(
2688 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002689 Register result = ToRegister(instr->result());
2690 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002691 __ mov(result, FieldOperand(input,
2692 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002693}
2694
2695
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002696void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2697 Register arguments = ToRegister(instr->arguments());
2698 Register length = ToRegister(instr->length());
2699 Operand index = ToOperand(instr->index());
2700 Register result = ToRegister(instr->result());
2701
2702 __ sub(length, index);
2703 DeoptimizeIf(below_equal, instr->environment());
2704
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002705 // There are two words between the frame pointer and the last argument.
2706 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002707 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2708}
2709
2710
2711void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002712 Register result = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002713
2714 // Load the result.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002715 __ mov(result,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002716 BuildFastArrayOperand(instr->elements(),
2717 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002718 instr->hydrogen()->key()->representation(),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002719 FAST_ELEMENTS,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002720 FixedArray::kHeaderSize - kHeapObjectTag,
2721 instr->additional_index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002722
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002723 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002724 if (instr->hydrogen()->RequiresHoleCheck()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002725 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
2726 __ test(result, Immediate(kSmiTagMask));
2727 DeoptimizeIf(not_equal, instr->environment());
2728 } else {
2729 __ cmp(result, factory()->the_hole_value());
2730 DeoptimizeIf(equal, instr->environment());
2731 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002732 }
2733}
2734
2735
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002736void LCodeGen::DoLoadKeyedFastDoubleElement(
2737 LLoadKeyedFastDoubleElement* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002738 XMMRegister result = ToDoubleRegister(instr->result());
2739
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002740 if (instr->hydrogen()->RequiresHoleCheck()) {
2741 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2742 sizeof(kHoleNanLower32);
2743 Operand hole_check_operand = BuildFastArrayOperand(
2744 instr->elements(), instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002745 instr->hydrogen()->key()->representation(),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002746 FAST_DOUBLE_ELEMENTS,
2747 offset,
2748 instr->additional_index());
2749 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
2750 DeoptimizeIf(equal, instr->environment());
2751 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002752
2753 Operand double_load_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002754 instr->elements(),
2755 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002756 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002757 FAST_DOUBLE_ELEMENTS,
2758 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
2759 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002760 __ movdbl(result, double_load_operand);
2761}
2762
2763
2764Operand LCodeGen::BuildFastArrayOperand(
danno@chromium.orgb6451162011-08-17 14:33:23 +00002765 LOperand* elements_pointer,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002766 LOperand* key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002767 Representation key_representation,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002768 ElementsKind elements_kind,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002769 uint32_t offset,
2770 uint32_t additional_index) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00002771 Register elements_pointer_reg = ToRegister(elements_pointer);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002772 int shift_size = ElementsKindToShiftSize(elements_kind);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002773 // Even though the HLoad/StoreKeyedFastElement instructions force the input
2774 // representation for the key to be an integer, the input gets replaced during
2775 // bound check elimination with the index argument to the bounds check, which
2776 // can be tagged, so that case must be handled here, too.
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002777 if (key_representation.IsTagged() && (shift_size >= 1)) {
2778 shift_size -= kSmiTagSize;
2779 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002780 if (key->IsConstantOperand()) {
2781 int constant_value = ToInteger32(LConstantOperand::cast(key));
2782 if (constant_value & 0xF0000000) {
2783 Abort("array index constant value too big");
2784 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002785 return Operand(elements_pointer_reg,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002786 ((constant_value + additional_index) << shift_size)
2787 + offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002788 } else {
2789 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002790 return Operand(elements_pointer_reg,
2791 ToRegister(key),
2792 scale_factor,
2793 offset + (additional_index << shift_size));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002794 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002795}
2796
2797
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002798void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2799 LLoadKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002800 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002801 LOperand* key = instr->key();
2802 if (!key->IsConstantOperand() &&
2803 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
2804 elements_kind)) {
2805 __ SmiUntag(ToRegister(key));
2806 }
2807 Operand operand(BuildFastArrayOperand(
2808 instr->external_pointer(),
2809 key,
2810 instr->hydrogen()->key()->representation(),
2811 elements_kind,
2812 0,
2813 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002814 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002815 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002816 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002817 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002818 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002819 __ movdbl(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002820 } else {
2821 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002822 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002823 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002824 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002825 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002826 case EXTERNAL_PIXEL_ELEMENTS:
2827 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002828 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002829 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002830 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002831 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002832 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002833 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002834 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002835 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002836 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002837 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002838 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002839 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002840 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002841 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2842 __ test(result, Operand(result));
2843 DeoptimizeIf(negative, instr->environment());
2844 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002845 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002846 case EXTERNAL_FLOAT_ELEMENTS:
2847 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002848 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002849 case FAST_ELEMENTS:
2850 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002851 case FAST_HOLEY_SMI_ELEMENTS:
2852 case FAST_HOLEY_ELEMENTS:
2853 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002854 case DICTIONARY_ELEMENTS:
2855 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002856 UNREACHABLE();
2857 break;
2858 }
2859 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002860}
2861
2862
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002864 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002865 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002866 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002867
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002868 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002869 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002870}
2871
2872
2873void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2874 Register result = ToRegister(instr->result());
2875
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002876 if (instr->hydrogen()->from_inlined()) {
2877 __ lea(result, Operand(esp, -2 * kPointerSize));
2878 } else {
2879 // Check for arguments adapter frame.
2880 Label done, adapted;
2881 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2882 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2883 __ cmp(Operand(result),
2884 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2885 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002886
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002887 // No arguments adaptor frame.
2888 __ mov(result, Operand(ebp));
2889 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002890
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002891 // Arguments adaptor frame present.
2892 __ bind(&adapted);
2893 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002894
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002895 // Result is the frame pointer for the frame if not adapted and for the real
2896 // frame below the adaptor frame if adapted.
2897 __ bind(&done);
2898 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002899}
2900
2901
2902void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002903 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002904 Register result = ToRegister(instr->result());
2905
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002906 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002907
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002908 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002909 __ cmp(ebp, elem);
2910 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002911 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002912
2913 // Arguments adaptor frame present. Get argument length from there.
2914 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2915 __ mov(result, Operand(result,
2916 ArgumentsAdaptorFrameConstants::kLengthOffset));
2917 __ SmiUntag(result);
2918
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002919 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002920 __ bind(&done);
2921}
2922
2923
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002924void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002925 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002926 Register function = ToRegister(instr->function());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002927 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002928
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002929 // If the receiver is null or undefined, we have to pass the global
2930 // object as a receiver to normal functions. Values have to be
2931 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002932 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002933
2934 // Do not transform the receiver to object for strict mode
2935 // functions.
2936 __ mov(scratch,
2937 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2938 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
2939 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
2940 __ j(not_equal, &receiver_ok, Label::kNear);
2941
2942 // Do not transform the receiver to object for builtins.
2943 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
2944 1 << SharedFunctionInfo::kNativeBitWithinByte);
2945 __ j(not_equal, &receiver_ok, Label::kNear);
2946
2947 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002948 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002949 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002950 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002951 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002952
2953 // The receiver should be a JS object.
2954 __ test(receiver, Immediate(kSmiTagMask));
2955 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002956 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002957 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002958 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002959
2960 __ bind(&global_object);
2961 // TODO(kmillikin): We have a hydrogen value for the global object. See
2962 // if it's better to use it than to explicitly fetch it from the context
2963 // here.
2964 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002965 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002966 __ mov(receiver,
2967 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002968 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00002969}
2970
2971
2972void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2973 Register receiver = ToRegister(instr->receiver());
2974 Register function = ToRegister(instr->function());
2975 Register length = ToRegister(instr->length());
2976 Register elements = ToRegister(instr->elements());
2977 ASSERT(receiver.is(eax)); // Used for parameter count.
2978 ASSERT(function.is(edi)); // Required by InvokeFunction.
2979 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002980
2981 // Copy the arguments to this function possibly from the
2982 // adaptor frame below it.
2983 const uint32_t kArgumentsLimit = 1 * KB;
2984 __ cmp(length, kArgumentsLimit);
2985 DeoptimizeIf(above, instr->environment());
2986
2987 __ push(receiver);
2988 __ mov(receiver, length);
2989
2990 // Loop through the arguments pushing them onto the execution
2991 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002992 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002993 // length is a small non-negative integer, due to the test above.
2994 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002995 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002996 __ bind(&loop);
2997 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2998 __ dec(length);
2999 __ j(not_zero, &loop);
3000
3001 // Invoke the function.
3002 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003003 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003004 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003005 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003006 SafepointGenerator safepoint_generator(
3007 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003008 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003009 __ InvokeFunction(function, actual, CALL_FUNCTION,
3010 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003011}
3012
3013
3014void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003015 LOperand* argument = instr->InputAt(0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003016 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003017}
3018
3019
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003020void LCodeGen::DoDrop(LDrop* instr) {
3021 __ Drop(instr->count());
3022}
3023
3024
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003025void LCodeGen::DoThisFunction(LThisFunction* instr) {
3026 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003027 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003028}
3029
3030
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003031void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003032 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003033 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003034}
3035
3036
3037void LCodeGen::DoOuterContext(LOuterContext* instr) {
3038 Register context = ToRegister(instr->context());
3039 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003040 __ mov(result,
3041 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003042}
3043
3044
yangguo@chromium.org56454712012-02-16 15:33:53 +00003045void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3046 ASSERT(ToRegister(instr->InputAt(0)).is(esi));
3047 __ push(esi); // The context is the first argument.
3048 __ push(Immediate(instr->hydrogen()->pairs()));
3049 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3050 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3051}
3052
3053
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003054void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3055 Register context = ToRegister(instr->context());
3056 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003057 __ mov(result,
3058 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003059}
3060
3061
3062void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003063 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003064 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003065 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003066}
3067
3068
3069void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3070 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003071 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003072 CallKind call_kind,
3073 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003074 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3075 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003076
3077 LPointerMap* pointers = instr->pointer_map();
3078 RecordPosition(pointers->position());
3079
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003080 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003081 if (edi_state == EDI_UNINITIALIZED) {
3082 __ LoadHeapObject(edi, function);
3083 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003084
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003085 // Change context.
3086 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003087
3088 // Set eax to arguments count if adaption is not needed. Assumes that eax
3089 // is available to write to at this point.
3090 if (!function->NeedsArgumentsAdaption()) {
3091 __ mov(eax, arity);
3092 }
3093
3094 // Invoke function directly.
3095 __ SetCallKind(ecx, call_kind);
3096 if (*function == *info()->closure()) {
3097 __ CallSelf();
3098 } else {
3099 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3100 }
3101 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3102 } else {
3103 // We need to adapt arguments.
3104 SafepointGenerator generator(
3105 this, pointers, Safepoint::kLazyDeopt);
3106 ParameterCount count(arity);
3107 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3108 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003109}
3110
3111
3112void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3113 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003114 CallKnownFunction(instr->function(),
3115 instr->arity(),
3116 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003117 CALL_AS_METHOD,
3118 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003119}
3120
3121
3122void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003123 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003124 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003126 DeoptimizeIf(not_equal, instr->environment());
3127
3128 Label done;
3129 Register tmp = input_reg.is(eax) ? ecx : eax;
3130 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3131
3132 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003133 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003134
3135 Label negative;
3136 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003137 // Check the sign of the argument. If the argument is positive, just
3138 // return it. We do not need to patch the stack since |input| and
3139 // |result| are the same register and |input| will be restored
3140 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003141 __ test(tmp, Immediate(HeapNumber::kSignMask));
3142 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003143 __ jmp(&done);
3144
3145 __ bind(&negative);
3146
3147 Label allocated, slow;
3148 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3149 __ jmp(&allocated);
3150
3151 // Slow case: Call the runtime system to do the number allocation.
3152 __ bind(&slow);
3153
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003154 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3155 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003156
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003157 // Set the pointer to the new heap number in tmp.
3158 if (!tmp.is(eax)) __ mov(tmp, eax);
3159
3160 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003161 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003162
3163 __ bind(&allocated);
3164 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3165 __ and_(tmp2, ~HeapNumber::kSignMask);
3166 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3167 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3168 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003169 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003170
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003171 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003172}
3173
3174
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003175void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003176 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003177 __ test(input_reg, Operand(input_reg));
3178 Label is_positive;
3179 __ j(not_sign, &is_positive);
3180 __ neg(input_reg);
3181 __ test(input_reg, Operand(input_reg));
3182 DeoptimizeIf(negative, instr->environment());
3183 __ bind(&is_positive);
3184}
3185
3186
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003187void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3188 // Class for deferred case.
3189 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3190 public:
3191 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3192 LUnaryMathOperation* instr)
3193 : LDeferredCode(codegen), instr_(instr) { }
3194 virtual void Generate() {
3195 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3196 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003197 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003198 private:
3199 LUnaryMathOperation* instr_;
3200 };
3201
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003202 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003203 Representation r = instr->hydrogen()->value()->representation();
3204
3205 if (r.IsDouble()) {
3206 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003207 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003208 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003209 __ subsd(scratch, input_reg);
3210 __ pand(input_reg, scratch);
3211 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003212 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003213 } else { // Tagged case.
3214 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003215 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003216 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003217 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003218 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003219 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003220 __ bind(deferred->exit());
3221 }
3222}
3223
3224
3225void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
3226 XMMRegister xmm_scratch = xmm0;
3227 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003228 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003229
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003230 if (CpuFeatures::IsSupported(SSE4_1)) {
3231 CpuFeatures::Scope scope(SSE4_1);
3232 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3233 // Deoptimize on negative zero.
3234 Label non_zero;
3235 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3236 __ ucomisd(input_reg, xmm_scratch);
3237 __ j(not_equal, &non_zero, Label::kNear);
3238 __ movmskpd(output_reg, input_reg);
3239 __ test(output_reg, Immediate(1));
3240 DeoptimizeIf(not_zero, instr->environment());
3241 __ bind(&non_zero);
3242 }
3243 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3244 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3245 // Overflow is signalled with minint.
3246 __ cmp(output_reg, 0x80000000u);
3247 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003248 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003249 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003250 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003251 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3252 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003253 DeoptimizeIf(parity_even, instr->environment());
3254 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003255
3256 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3257 // Check for negative zero.
3258 Label positive_sign;
3259 __ j(above, &positive_sign, Label::kNear);
3260 __ movmskpd(output_reg, input_reg);
3261 __ test(output_reg, Immediate(1));
3262 DeoptimizeIf(not_zero, instr->environment());
3263 __ Set(output_reg, Immediate(0));
3264 __ jmp(&done, Label::kNear);
3265 __ bind(&positive_sign);
3266 }
3267
3268 // Use truncating instruction (OK because input is positive).
3269 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003270 // Overflow is signalled with minint.
3271 __ cmp(output_reg, 0x80000000u);
3272 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003273 __ jmp(&done, Label::kNear);
3274
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003275 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003276 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003277 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003278 __ cvttsd2si(output_reg, Operand(input_reg));
3279 __ cvtsi2sd(xmm_scratch, output_reg);
3280 __ ucomisd(input_reg, xmm_scratch);
3281 __ j(equal, &done, Label::kNear);
3282 __ sub(output_reg, Immediate(1));
3283 DeoptimizeIf(overflow, instr->environment());
3284
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003285 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003286 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003287}
3288
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003289void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
3290 XMMRegister xmm_scratch = xmm0;
3291 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003292 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003293
danno@chromium.org160a7b02011-04-18 15:51:38 +00003294 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003295 // xmm_scratch = 0.5
3296 ExternalReference one_half = ExternalReference::address_of_one_half();
3297 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003298 __ ucomisd(xmm_scratch, input_reg);
3299 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003300 // xmm_scratch = input + 0.5
3301 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003302
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003303 // Compute Math.floor(value + 0.5).
3304 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003305 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003306
3307 // Overflow is signalled with minint.
3308 __ cmp(output_reg, 0x80000000u);
3309 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003310 __ jmp(&done);
3311
3312 __ bind(&below_half);
3313
3314 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3315 // we can ignore the difference between a result of -0 and +0.
3316 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3317 // If the sign is positive, we return +0.
3318 __ movmskpd(output_reg, input_reg);
3319 __ test(output_reg, Immediate(1));
3320 DeoptimizeIf(not_zero, instr->environment());
3321 } else {
3322 // If the input is >= -0.5, we return +0.
3323 __ mov(output_reg, Immediate(0xBF000000));
3324 __ movd(xmm_scratch, Operand(output_reg));
3325 __ cvtss2sd(xmm_scratch, xmm_scratch);
3326 __ ucomisd(input_reg, xmm_scratch);
3327 DeoptimizeIf(below, instr->environment());
3328 }
3329 __ Set(output_reg, Immediate(0));
3330 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003331}
3332
3333
3334void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003335 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003336 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3337 __ sqrtsd(input_reg, input_reg);
3338}
3339
3340
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003341void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003342 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003343 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003344 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003345 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003346
3347 // Note that according to ECMA-262 15.8.2.13:
3348 // Math.pow(-Infinity, 0.5) == Infinity
3349 // Math.sqrt(-Infinity) == NaN
3350 Label done, sqrt;
3351 // Check base for -Infinity. According to IEEE-754, single-precision
3352 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3353 __ mov(scratch, 0xFF800000);
3354 __ movd(xmm_scratch, scratch);
3355 __ cvtss2sd(xmm_scratch, xmm_scratch);
3356 __ ucomisd(input_reg, xmm_scratch);
3357 // Comparing -Infinity with NaN results in "unordered", which sets the
3358 // zero flag as if both were equal. However, it also sets the carry flag.
3359 __ j(not_equal, &sqrt, Label::kNear);
3360 __ j(carry, &sqrt, Label::kNear);
3361 // If input is -Infinity, return Infinity.
3362 __ xorps(input_reg, input_reg);
3363 __ subsd(input_reg, xmm_scratch);
3364 __ jmp(&done, Label::kNear);
3365
3366 // Square root.
3367 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003368 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003369 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003370 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003371 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003372}
3373
3374
3375void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003376 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003377 // Having marked this as a call, we can use any registers.
3378 // Just make sure that the input/output registers are the expected ones.
3379 ASSERT(!instr->InputAt(1)->IsDoubleRegister() ||
3380 ToDoubleRegister(instr->InputAt(1)).is(xmm1));
3381 ASSERT(!instr->InputAt(1)->IsRegister() ||
3382 ToRegister(instr->InputAt(1)).is(eax));
3383 ASSERT(ToDoubleRegister(instr->InputAt(0)).is(xmm2));
3384 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003386 if (exponent_type.IsTagged()) {
3387 Label no_deopt;
3388 __ JumpIfSmi(eax, &no_deopt);
3389 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003390 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003391 __ bind(&no_deopt);
3392 MathPowStub stub(MathPowStub::TAGGED);
3393 __ CallStub(&stub);
3394 } else if (exponent_type.IsInteger32()) {
3395 MathPowStub stub(MathPowStub::INTEGER);
3396 __ CallStub(&stub);
3397 } else {
3398 ASSERT(exponent_type.IsDouble());
3399 MathPowStub stub(MathPowStub::DOUBLE);
3400 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003401 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003402}
3403
3404
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003405void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003406 class DeferredDoRandom: public LDeferredCode {
3407 public:
3408 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3409 : LDeferredCode(codegen), instr_(instr) { }
3410 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3411 virtual LInstruction* instr() { return instr_; }
3412 private:
3413 LRandom* instr_;
3414 };
3415
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003416 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003417
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003418 // Having marked this instruction as a call we can use any
3419 // registers.
3420 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3421 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003422 // Assert that the register size is indeed the size of each seed.
3423 static const int kSeedSize = sizeof(uint32_t);
3424 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003425
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003426 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003427 static const int kRandomSeedOffset =
3428 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3429 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003430 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003431
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003432 // Load state[0].
3433 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3434 // If state[0] == 0, call runtime to initialize seeds.
3435 __ test(ecx, ecx);
3436 __ j(zero, deferred->entry());
3437 // Load state[1].
3438 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3439 // ecx: state[0]
3440 // eax: state[1]
3441
3442 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3443 __ movzx_w(edx, ecx);
3444 __ imul(edx, edx, 18273);
3445 __ shr(ecx, 16);
3446 __ add(ecx, edx);
3447 // Save state[0].
3448 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3449
3450 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3451 __ movzx_w(edx, eax);
3452 __ imul(edx, edx, 36969);
3453 __ shr(eax, 16);
3454 __ add(eax, edx);
3455 // Save state[1].
3456 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3457
3458 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3459 __ shl(ecx, 14);
3460 __ and_(eax, Immediate(0x3FFFF));
3461 __ add(eax, ecx);
3462
3463 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003464 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3465 // by computing:
3466 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3467 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3468 __ movd(xmm2, ebx);
3469 __ movd(xmm1, eax);
3470 __ cvtss2sd(xmm2, xmm2);
3471 __ xorps(xmm1, xmm2);
3472 __ subsd(xmm1, xmm2);
3473}
3474
3475
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003476void LCodeGen::DoDeferredRandom(LRandom* instr) {
3477 __ PrepareCallCFunction(1, ebx);
3478 __ mov(Operand(esp, 0), eax);
3479 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3480 // Return value is in eax.
3481}
3482
3483
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003484void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003485 ASSERT(instr->value()->Equals(instr->result()));
3486 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003487 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003488 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003489 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003490 __ j(above, &positive, Label::kNear);
3491 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003492 ExternalReference nan =
3493 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003494 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003495 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003496 __ bind(&zero);
3497 __ push(Immediate(0xFFF00000));
3498 __ push(Immediate(0));
3499 __ movdbl(input_reg, Operand(esp, 0));
3500 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003501 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003502 __ bind(&positive);
3503 __ fldln2();
3504 __ sub(Operand(esp), Immediate(kDoubleSize));
3505 __ movdbl(Operand(esp, 0), input_reg);
3506 __ fld_d(Operand(esp, 0));
3507 __ fyl2x();
3508 __ fstp_d(Operand(esp, 0));
3509 __ movdbl(input_reg, Operand(esp, 0));
3510 __ add(Operand(esp), Immediate(kDoubleSize));
3511 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003512}
3513
3514
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003515void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3516 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3517 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3518 TranscendentalCacheStub::UNTAGGED);
3519 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3520}
3521
3522
whesse@chromium.org023421e2010-12-21 12:19:12 +00003523void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3524 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3525 TranscendentalCacheStub stub(TranscendentalCache::COS,
3526 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003527 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003528}
3529
3530
3531void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3532 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3533 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3534 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003535 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003536}
3537
3538
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003539void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3540 switch (instr->op()) {
3541 case kMathAbs:
3542 DoMathAbs(instr);
3543 break;
3544 case kMathFloor:
3545 DoMathFloor(instr);
3546 break;
3547 case kMathRound:
3548 DoMathRound(instr);
3549 break;
3550 case kMathSqrt:
3551 DoMathSqrt(instr);
3552 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003553 case kMathCos:
3554 DoMathCos(instr);
3555 break;
3556 case kMathSin:
3557 DoMathSin(instr);
3558 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003559 case kMathTan:
3560 DoMathTan(instr);
3561 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003562 case kMathLog:
3563 DoMathLog(instr);
3564 break;
3565
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003566 default:
3567 UNREACHABLE();
3568 }
3569}
3570
3571
danno@chromium.org160a7b02011-04-18 15:51:38 +00003572void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3573 ASSERT(ToRegister(instr->context()).is(esi));
3574 ASSERT(ToRegister(instr->function()).is(edi));
3575 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003576
3577 if (instr->known_function().is_null()) {
3578 LPointerMap* pointers = instr->pointer_map();
3579 RecordPosition(pointers->position());
3580 SafepointGenerator generator(
3581 this, pointers, Safepoint::kLazyDeopt);
3582 ParameterCount count(instr->arity());
3583 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3584 } else {
3585 CallKnownFunction(instr->known_function(),
3586 instr->arity(),
3587 instr,
3588 CALL_AS_METHOD,
3589 EDI_CONTAINS_TARGET);
3590 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003591}
3592
3593
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003594void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003595 ASSERT(ToRegister(instr->context()).is(esi));
3596 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003597 ASSERT(ToRegister(instr->result()).is(eax));
3598
3599 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003600 Handle<Code> ic =
3601 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003602 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603}
3604
3605
3606void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003607 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003608 ASSERT(ToRegister(instr->result()).is(eax));
3609
3610 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003611 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3612 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003613 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003614 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003615 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003616}
3617
3618
3619void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003620 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003621 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622 ASSERT(ToRegister(instr->result()).is(eax));
3623
3624 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003625 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003626 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003627}
3628
3629
3630void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003631 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003632 ASSERT(ToRegister(instr->result()).is(eax));
3633
3634 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003635 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3636 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003637 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003638 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003639 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003640}
3641
3642
3643void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3644 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003645 CallKnownFunction(instr->target(),
3646 instr->arity(),
3647 instr,
3648 CALL_AS_FUNCTION,
3649 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003650}
3651
3652
3653void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003654 ASSERT(ToRegister(instr->context()).is(esi));
3655 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003656 ASSERT(ToRegister(instr->result()).is(eax));
3657
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003658 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003659 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003660 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003661}
3662
3663
3664void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003665 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003666}
3667
3668
3669void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3670 Register object = ToRegister(instr->object());
3671 Register value = ToRegister(instr->value());
3672 int offset = instr->offset();
3673
3674 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00003675 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
3676 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3677 } else {
3678 Register temp = ToRegister(instr->TempAt(0));
3679 Register temp_map = ToRegister(instr->TempAt(1));
3680 __ mov(temp_map, instr->transition());
3681 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
3682 // Update the write barrier for the map field.
3683 __ RecordWriteField(object,
3684 HeapObject::kMapOffset,
3685 temp_map,
3686 temp,
3687 kSaveFPRegs,
3688 OMIT_REMEMBERED_SET,
3689 OMIT_SMI_CHECK);
3690 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003691 }
3692
3693 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003694 HType type = instr->hydrogen()->value()->type();
3695 SmiCheck check_needed =
3696 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003697 if (instr->is_in_object()) {
3698 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003699 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003700 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003701 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003702 __ RecordWriteField(object,
3703 offset,
3704 value,
3705 temp,
3706 kSaveFPRegs,
3707 EMIT_REMEMBERED_SET,
3708 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003709 }
3710 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003711 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003712 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3713 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003714 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003715 // Update the write barrier for the properties array.
3716 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003717 __ RecordWriteField(temp,
3718 offset,
3719 value,
3720 object,
3721 kSaveFPRegs,
3722 EMIT_REMEMBERED_SET,
3723 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003724 }
3725 }
3726}
3727
3728
3729void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003730 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003731 ASSERT(ToRegister(instr->object()).is(edx));
3732 ASSERT(ToRegister(instr->value()).is(eax));
3733
3734 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003735 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003736 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3737 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003738 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003739}
3740
3741
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003742void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
3743 HValue* value,
3744 LOperand* operand) {
3745 if (value->representation().IsTagged() && !value->type().IsSmi()) {
3746 if (operand->IsRegister()) {
3747 __ test(ToRegister(operand), Immediate(kSmiTagMask));
3748 } else {
3749 __ test(ToOperand(operand), Immediate(kSmiTagMask));
3750 }
3751 DeoptimizeIf(not_zero, environment);
3752 }
3753}
3754
3755
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003756void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003757 DeoptIfTaggedButNotSmi(instr->environment(),
3758 instr->hydrogen()->length(),
3759 instr->length());
3760 DeoptIfTaggedButNotSmi(instr->environment(),
3761 instr->hydrogen()->index(),
3762 instr->index());
danno@chromium.orgb6451162011-08-17 14:33:23 +00003763 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003764 int constant_index =
3765 ToInteger32(LConstantOperand::cast(instr->index()));
3766 if (instr->hydrogen()->length()->representation().IsTagged()) {
3767 __ cmp(ToOperand(instr->length()),
3768 Immediate(Smi::FromInt(constant_index)));
3769 } else {
3770 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
3771 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003772 DeoptimizeIf(below_equal, instr->environment());
3773 } else {
3774 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3775 DeoptimizeIf(above_equal, instr->environment());
3776 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003777}
3778
3779
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003780void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3781 LStoreKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003782 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003783 LOperand* key = instr->key();
3784 if (!key->IsConstantOperand() &&
3785 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3786 elements_kind)) {
3787 __ SmiUntag(ToRegister(key));
3788 }
3789 Operand operand(BuildFastArrayOperand(
3790 instr->external_pointer(),
3791 key,
3792 instr->hydrogen()->key()->representation(),
3793 elements_kind,
3794 0,
3795 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003796 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003797 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003798 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003799 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003800 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003801 } else {
3802 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003803 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003804 case EXTERNAL_PIXEL_ELEMENTS:
3805 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3806 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003807 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003808 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003809 case EXTERNAL_SHORT_ELEMENTS:
3810 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003811 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003812 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003813 case EXTERNAL_INT_ELEMENTS:
3814 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003815 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003816 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003817 case EXTERNAL_FLOAT_ELEMENTS:
3818 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003819 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003820 case FAST_ELEMENTS:
3821 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003822 case FAST_HOLEY_SMI_ELEMENTS:
3823 case FAST_HOLEY_ELEMENTS:
3824 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003825 case DICTIONARY_ELEMENTS:
3826 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003827 UNREACHABLE();
3828 break;
3829 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003830 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003831}
3832
3833
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003834void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3835 Register value = ToRegister(instr->value());
3836 Register elements = ToRegister(instr->object());
3837 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3838
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003839 Operand operand = BuildFastArrayOperand(
3840 instr->object(),
3841 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003842 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003843 FAST_ELEMENTS,
3844 FixedArray::kHeaderSize - kHeapObjectTag,
3845 instr->additional_index());
3846 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003847
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003848 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003849 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003850 HType type = instr->hydrogen()->value()->type();
3851 SmiCheck check_needed =
3852 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003853 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003854 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003855 __ RecordWrite(elements,
3856 key,
3857 value,
3858 kSaveFPRegs,
3859 EMIT_REMEMBERED_SET,
3860 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003861 }
3862}
3863
3864
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003865void LCodeGen::DoStoreKeyedFastDoubleElement(
3866 LStoreKeyedFastDoubleElement* instr) {
3867 XMMRegister value = ToDoubleRegister(instr->value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003868
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003869 if (instr->NeedsCanonicalization()) {
3870 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003871
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003872 __ ucomisd(value, value);
3873 __ j(parity_odd, &have_value); // NaN.
3874
3875 ExternalReference canonical_nan_reference =
3876 ExternalReference::address_of_canonical_non_hole_nan();
3877 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
3878 __ bind(&have_value);
3879 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003880
3881 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003882 instr->elements(),
3883 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003884 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003885 FAST_DOUBLE_ELEMENTS,
3886 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3887 instr->additional_index());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003888 __ movdbl(double_store_operand, value);
3889}
3890
3891
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003892void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003893 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003894 ASSERT(ToRegister(instr->object()).is(edx));
3895 ASSERT(ToRegister(instr->key()).is(ecx));
3896 ASSERT(ToRegister(instr->value()).is(eax));
3897
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003898 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003899 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3900 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003901 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003902}
3903
3904
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003905void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
3906 Register object_reg = ToRegister(instr->object());
3907 Register new_map_reg = ToRegister(instr->new_map_reg());
3908
3909 Handle<Map> from_map = instr->original_map();
3910 Handle<Map> to_map = instr->transitioned_map();
3911 ElementsKind from_kind = from_map->elements_kind();
3912 ElementsKind to_kind = to_map->elements_kind();
3913
3914 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003915 bool is_simple_map_transition =
3916 IsSimpleMapChangeTransition(from_kind, to_kind);
3917 Label::Distance branch_distance =
3918 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003919 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003920 __ j(not_equal, &not_applicable, branch_distance);
3921 if (is_simple_map_transition) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003922 Register object_reg = ToRegister(instr->object());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003923 Handle<Map> map = instr->hydrogen()->transitioned_map();
3924 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
3925 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003926 // Write barrier.
3927 ASSERT_NE(instr->temp_reg(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003928 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
3929 ToRegister(instr->temp_reg()),
3930 kDontSaveFPRegs);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003931 } else if (IsFastSmiElementsKind(from_kind) &&
3932 IsFastDoubleElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003933 __ mov(new_map_reg, to_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003934 Register fixed_object_reg = ToRegister(instr->temp_reg());
3935 ASSERT(fixed_object_reg.is(edx));
3936 ASSERT(new_map_reg.is(ebx));
3937 __ mov(fixed_object_reg, object_reg);
3938 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
3939 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003940 } else if (IsFastDoubleElementsKind(from_kind) &&
3941 IsFastObjectElementsKind(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()->TransitionElementsDoubleToObject(),
3948 RelocInfo::CODE_TARGET, instr);
3949 } else {
3950 UNREACHABLE();
3951 }
3952 __ bind(&not_applicable);
3953}
3954
3955
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003956void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3957 class DeferredStringCharCodeAt: public LDeferredCode {
3958 public:
3959 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3960 : LDeferredCode(codegen), instr_(instr) { }
3961 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003962 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003963 private:
3964 LStringCharCodeAt* instr_;
3965 };
3966
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003967 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003968 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003969
erikcorry0ad885c2011-11-21 13:51:57 +00003970 StringCharLoadGenerator::Generate(masm(),
3971 factory(),
3972 ToRegister(instr->string()),
3973 ToRegister(instr->index()),
3974 ToRegister(instr->result()),
3975 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003976 __ bind(deferred->exit());
3977}
3978
3979
3980void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3981 Register string = ToRegister(instr->string());
3982 Register result = ToRegister(instr->result());
3983
3984 // TODO(3095996): Get rid of this. For now, we need to make the
3985 // result register contain a valid pointer because it is already
3986 // contained in the register pointer map.
3987 __ Set(result, Immediate(0));
3988
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003989 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003990 __ push(string);
3991 // Push the index as a smi. This is safe because of the checks in
3992 // DoStringCharCodeAt above.
3993 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3994 if (instr->index()->IsConstantOperand()) {
3995 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3996 __ push(Immediate(Smi::FromInt(const_index)));
3997 } else {
3998 Register index = ToRegister(instr->index());
3999 __ SmiTag(index);
4000 __ push(index);
4001 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004002 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4003 instr, instr->context());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004004 if (FLAG_debug_code) {
4005 __ AbortIfNotSmi(eax);
4006 }
4007 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004008 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004009}
4010
4011
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004012void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4013 class DeferredStringCharFromCode: public LDeferredCode {
4014 public:
4015 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4016 : LDeferredCode(codegen), instr_(instr) { }
4017 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004018 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004019 private:
4020 LStringCharFromCode* instr_;
4021 };
4022
4023 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004024 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004025
4026 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4027 Register char_code = ToRegister(instr->char_code());
4028 Register result = ToRegister(instr->result());
4029 ASSERT(!char_code.is(result));
4030
4031 __ cmp(char_code, String::kMaxAsciiCharCode);
4032 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004033 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004034 __ mov(result, FieldOperand(result,
4035 char_code, times_pointer_size,
4036 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004037 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004038 __ j(equal, deferred->entry());
4039 __ bind(deferred->exit());
4040}
4041
4042
4043void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4044 Register char_code = ToRegister(instr->char_code());
4045 Register result = ToRegister(instr->result());
4046
4047 // TODO(3095996): Get rid of this. For now, we need to make the
4048 // result register contain a valid pointer because it is already
4049 // contained in the register pointer map.
4050 __ Set(result, Immediate(0));
4051
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004052 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004053 __ SmiTag(char_code);
4054 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004055 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004056 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004057}
4058
4059
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004060void LCodeGen::DoStringLength(LStringLength* instr) {
4061 Register string = ToRegister(instr->string());
4062 Register result = ToRegister(instr->result());
4063 __ mov(result, FieldOperand(string, String::kLengthOffset));
4064}
4065
4066
danno@chromium.org160a7b02011-04-18 15:51:38 +00004067void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004068 EmitPushTaggedOperand(instr->left());
4069 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004070 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004071 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004072}
4073
4074
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004075void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004076 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004077 ASSERT(input->IsRegister() || input->IsStackSlot());
4078 LOperand* output = instr->result();
4079 ASSERT(output->IsDoubleRegister());
4080 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4081}
4082
4083
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004084void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
4085 LOperand* input = instr->InputAt(0);
4086 LOperand* output = instr->result();
4087 LOperand* temp = instr->TempAt(0);
4088
4089 __ LoadUint32(ToDoubleRegister(output),
4090 ToRegister(input),
4091 ToDoubleRegister(temp));
4092}
4093
4094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004095void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4096 class DeferredNumberTagI: public LDeferredCode {
4097 public:
4098 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4099 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004100 virtual void Generate() {
4101 codegen()->DoDeferredNumberTagI(instr_,
4102 instr_->InputAt(0),
4103 SIGNED_INT32);
4104 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004105 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004106 private:
4107 LNumberTagI* instr_;
4108 };
4109
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004110 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004111 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4112 Register reg = ToRegister(input);
4113
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004114 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004115 __ SmiTag(reg);
4116 __ j(overflow, deferred->entry());
4117 __ bind(deferred->exit());
4118}
4119
4120
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004121void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4122 class DeferredNumberTagU: public LDeferredCode {
4123 public:
4124 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4125 : LDeferredCode(codegen), instr_(instr) { }
4126 virtual void Generate() {
4127 codegen()->DoDeferredNumberTagI(instr_,
4128 instr_->InputAt(0),
4129 UNSIGNED_INT32);
4130 }
4131 virtual LInstruction* instr() { return instr_; }
4132 private:
4133 LNumberTagU* instr_;
4134 };
4135
4136 LOperand* input = instr->InputAt(0);
4137 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4138 Register reg = ToRegister(input);
4139
4140 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4141 __ cmp(reg, Immediate(Smi::kMaxValue));
4142 __ j(above, deferred->entry());
4143 __ SmiTag(reg);
4144 __ bind(deferred->exit());
4145}
4146
4147
4148void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4149 LOperand* value,
4150 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004151 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004152 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004153 Register tmp = reg.is(eax) ? ecx : eax;
4154
4155 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004156 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004157
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004158 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004159
4160 if (signedness == SIGNED_INT32) {
4161 // There was overflow, so bits 30 and 31 of the original integer
4162 // disagree. Try to allocate a heap number in new space and store
4163 // the value in there. If that fails, call the runtime system.
4164 __ SmiUntag(reg);
4165 __ xor_(reg, 0x80000000);
4166 __ cvtsi2sd(xmm0, Operand(reg));
4167 } else {
4168 __ LoadUint32(xmm0, reg, xmm1);
4169 }
4170
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004171 if (FLAG_inline_new) {
4172 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004173 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004174 }
4175
4176 // Slow case: Call the runtime system to do the number allocation.
4177 __ bind(&slow);
4178
4179 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4180 // register is stored, as this register is in the pointer map, but contains an
4181 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004182 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004183 // NumberTagI and NumberTagD use the context from the frame, rather than
4184 // the environment's HContext or HInlinedContext value.
4185 // They only call Runtime::kAllocateHeapNumber.
4186 // The corresponding HChange instructions are added in a phase that does
4187 // not have easy access to the local context.
4188 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4189 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4190 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004191 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192 if (!reg.is(eax)) __ mov(reg, eax);
4193
4194 // Done. Put the value in xmm0 into the value of the allocated heap
4195 // number.
4196 __ bind(&done);
4197 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004198 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004199}
4200
4201
4202void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4203 class DeferredNumberTagD: public LDeferredCode {
4204 public:
4205 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4206 : LDeferredCode(codegen), instr_(instr) { }
4207 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004208 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004209 private:
4210 LNumberTagD* instr_;
4211 };
4212
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004213 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004214 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004215 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004216
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004217 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004218 if (FLAG_inline_new) {
4219 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4220 } else {
4221 __ jmp(deferred->entry());
4222 }
4223 __ bind(deferred->exit());
4224 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4225}
4226
4227
4228void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4229 // TODO(3095996): Get rid of this. For now, we need to make the
4230 // result register contain a valid pointer because it is already
4231 // contained in the register pointer map.
4232 Register reg = ToRegister(instr->result());
4233 __ Set(reg, Immediate(0));
4234
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004235 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004236 // NumberTagI and NumberTagD use the context from the frame, rather than
4237 // the environment's HContext or HInlinedContext value.
4238 // They only call Runtime::kAllocateHeapNumber.
4239 // The corresponding HChange instructions are added in a phase that does
4240 // not have easy access to the local context.
4241 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4242 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004243 RecordSafepointWithRegisters(
4244 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004245 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004246}
4247
4248
4249void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004250 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004251 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4252 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4253 __ SmiTag(ToRegister(input));
4254}
4255
4256
4257void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004258 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004259 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4260 if (instr->needs_check()) {
4261 __ test(ToRegister(input), Immediate(kSmiTagMask));
4262 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004263 } else {
4264 if (FLAG_debug_code) {
4265 __ AbortIfNotSmi(ToRegister(input));
4266 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004267 }
4268 __ SmiUntag(ToRegister(input));
4269}
4270
4271
4272void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004273 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004274 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004275 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004276 bool deoptimize_on_minus_zero,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004277 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004278 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004279
4280 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004281 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004282
4283 // Heap number map check.
4284 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004285 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004286 if (deoptimize_on_undefined) {
4287 DeoptimizeIf(not_equal, env);
4288 } else {
4289 Label heap_number;
4290 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004291
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004292 __ cmp(input_reg, factory()->undefined_value());
4293 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004294
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004295 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004296 ExternalReference nan =
4297 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004298 __ movdbl(result_reg, Operand::StaticVariable(nan));
4299 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004300
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004301 __ bind(&heap_number);
4302 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004303 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004304 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004305 if (deoptimize_on_minus_zero) {
4306 XMMRegister xmm_scratch = xmm0;
4307 __ xorps(xmm_scratch, xmm_scratch);
4308 __ ucomisd(result_reg, xmm_scratch);
4309 __ j(not_zero, &done, Label::kNear);
4310 __ movmskpd(temp_reg, result_reg);
4311 __ test_b(temp_reg, 1);
4312 DeoptimizeIf(not_zero, env);
4313 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004314 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004315
4316 // Smi to XMM conversion
4317 __ bind(&load_smi);
4318 __ SmiUntag(input_reg); // Untag smi before converting to float.
4319 __ cvtsi2sd(result_reg, Operand(input_reg));
4320 __ SmiTag(input_reg); // Retag smi.
4321 __ bind(&done);
4322}
4323
4324
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004325void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004326 Label done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004327 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004328
4329 // Heap number map check.
4330 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004331 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004332
4333 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004334 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004335 // Check for undefined. Undefined is converted to zero for truncating
4336 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004338 DeoptimizeIf(not_equal, instr->environment());
4339 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004340 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004341
4342 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004343 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004344 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004345 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004346 // Use more powerful conversion when sse3 is available.
4347 // Load x87 register with heap number.
4348 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4349 // Get exponent alone and check for too-big exponent.
4350 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
4351 __ and_(input_reg, HeapNumber::kExponentMask);
4352 const uint32_t kTooBigExponent =
4353 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4354 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004355 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004356 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004357 __ fstp(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004358 DeoptimizeIf(no_condition, instr->environment());
4359
4360 // Reserve space for 64 bit answer.
4361 __ bind(&convert);
4362 __ sub(Operand(esp), Immediate(kDoubleSize));
4363 // Do conversion, which cannot fail because we checked the exponent.
4364 __ fisttp_d(Operand(esp, 0));
4365 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
4366 __ add(Operand(esp), Immediate(kDoubleSize));
4367 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004368 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004369 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4370 __ cvttsd2si(input_reg, Operand(xmm0));
4371 __ cmp(input_reg, 0x80000000u);
4372 __ j(not_equal, &done);
4373 // Check if the input was 0x8000000 (kMinInt).
4374 // If no, then we got an overflow and we deoptimize.
4375 ExternalReference min_int = ExternalReference::address_of_min_int();
4376 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
4377 __ ucomisd(xmm_temp, xmm0);
4378 DeoptimizeIf(not_equal, instr->environment());
4379 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4380 }
4381 } else {
4382 // Deoptimize if we don't have a heap number.
4383 DeoptimizeIf(not_equal, instr->environment());
4384
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004385 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004386 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4387 __ cvttsd2si(input_reg, Operand(xmm0));
4388 __ cvtsi2sd(xmm_temp, Operand(input_reg));
4389 __ ucomisd(xmm0, xmm_temp);
4390 DeoptimizeIf(not_equal, instr->environment());
4391 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4392 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4393 __ test(input_reg, Operand(input_reg));
4394 __ j(not_zero, &done);
4395 __ movmskpd(input_reg, xmm0);
4396 __ and_(input_reg, 1);
4397 DeoptimizeIf(not_zero, instr->environment());
4398 }
4399 }
4400 __ bind(&done);
4401}
4402
4403
4404void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004405 class DeferredTaggedToI: public LDeferredCode {
4406 public:
4407 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4408 : LDeferredCode(codegen), instr_(instr) { }
4409 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4410 virtual LInstruction* instr() { return instr_; }
4411 private:
4412 LTaggedToI* instr_;
4413 };
4414
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004415 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004416 ASSERT(input->IsRegister());
4417 ASSERT(input->Equals(instr->result()));
4418
4419 Register input_reg = ToRegister(input);
4420
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004421 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004422
4423 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004424 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004425
4426 // Smi to int32 conversion
4427 __ SmiUntag(input_reg); // Untag smi.
4428
4429 __ bind(deferred->exit());
4430}
4431
4432
4433void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004434 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004435 ASSERT(input->IsRegister());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004436 LOperand* temp = instr->TempAt(0);
4437 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004438 LOperand* result = instr->result();
4439 ASSERT(result->IsDoubleRegister());
4440
4441 Register input_reg = ToRegister(input);
4442 XMMRegister result_reg = ToDoubleRegister(result);
4443
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004444 bool deoptimize_on_minus_zero =
4445 instr->hydrogen()->deoptimize_on_minus_zero();
4446 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
4447
4448 EmitNumberUntagD(input_reg,
4449 temp_reg,
4450 result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004451 instr->hydrogen()->deoptimize_on_undefined(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004452 deoptimize_on_minus_zero,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004453 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004454}
4455
4456
4457void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004458 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004459 ASSERT(input->IsDoubleRegister());
4460 LOperand* result = instr->result();
4461 ASSERT(result->IsRegister());
4462
4463 XMMRegister input_reg = ToDoubleRegister(input);
4464 Register result_reg = ToRegister(result);
4465
4466 if (instr->truncating()) {
4467 // Performs a truncating conversion of a floating point number as used by
4468 // the JS bitwise operations.
4469 __ cvttsd2si(result_reg, Operand(input_reg));
4470 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004471 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004472 // This will deoptimize if the exponent of the input in out of range.
4473 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004474 Label convert, done;
4475 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004476 __ sub(Operand(esp), Immediate(kDoubleSize));
4477 __ movdbl(Operand(esp, 0), input_reg);
4478 // Get exponent alone and check for too-big exponent.
4479 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
4480 __ and_(result_reg, HeapNumber::kExponentMask);
4481 const uint32_t kTooBigExponent =
4482 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4483 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004484 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004485 __ add(Operand(esp), Immediate(kDoubleSize));
4486 DeoptimizeIf(no_condition, instr->environment());
4487 __ bind(&convert);
4488 // Do conversion, which cannot fail because we checked the exponent.
4489 __ fld_d(Operand(esp, 0));
4490 __ fisttp_d(Operand(esp, 0));
4491 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
4492 __ add(Operand(esp), Immediate(kDoubleSize));
4493 __ bind(&done);
4494 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004495 Label done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004496 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004497 XMMRegister xmm_scratch = xmm0;
4498
4499 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
4500 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004501 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004502
4503 // Get high 32 bits of the input in result_reg and temp_reg.
4504 __ pshufd(xmm_scratch, input_reg, 1);
4505 __ movd(Operand(temp_reg), xmm_scratch);
4506 __ mov(result_reg, temp_reg);
4507
4508 // Prepare negation mask in temp_reg.
4509 __ sar(temp_reg, kBitsPerInt - 1);
4510
4511 // Extract the exponent from result_reg and subtract adjusted
4512 // bias from it. The adjustment is selected in a way such that
4513 // when the difference is zero, the answer is in the low 32 bits
4514 // of the input, otherwise a shift has to be performed.
4515 __ shr(result_reg, HeapNumber::kExponentShift);
4516 __ and_(result_reg,
4517 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
4518 __ sub(Operand(result_reg),
4519 Immediate(HeapNumber::kExponentBias +
4520 HeapNumber::kExponentBits +
4521 HeapNumber::kMantissaBits));
4522 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
4523 // special exponents.
4524 DeoptimizeIf(greater, instr->environment());
4525
4526 // Zero out the sign and the exponent in the input (by shifting
4527 // it to the left) and restore the implicit mantissa bit,
4528 // i.e. convert the input to unsigned int64 shifted left by
4529 // kExponentBits.
4530 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
4531 // Minus zero has the most significant bit set and the other
4532 // bits cleared.
4533 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
4534 __ psllq(input_reg, HeapNumber::kExponentBits);
4535 __ por(input_reg, xmm_scratch);
4536
4537 // Get the amount to shift the input right in xmm_scratch.
4538 __ neg(result_reg);
4539 __ movd(xmm_scratch, Operand(result_reg));
4540
4541 // Shift the input right and extract low 32 bits.
4542 __ psrlq(input_reg, xmm_scratch);
4543 __ movd(Operand(result_reg), input_reg);
4544
4545 // Use the prepared mask in temp_reg to negate the result if necessary.
4546 __ xor_(result_reg, Operand(temp_reg));
4547 __ sub(result_reg, Operand(temp_reg));
4548 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004549 }
4550 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004551 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004552 __ cvttsd2si(result_reg, Operand(input_reg));
4553 __ cvtsi2sd(xmm0, Operand(result_reg));
4554 __ ucomisd(xmm0, input_reg);
4555 DeoptimizeIf(not_equal, instr->environment());
4556 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4557 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4558 // The integer converted back is equal to the original. We
4559 // only have to test if we got -0 as an input.
4560 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004561 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004562 __ movmskpd(result_reg, input_reg);
4563 // Bit 0 contains the sign of the double in input_reg.
4564 // If input was positive, we are ok and return 0, otherwise
4565 // deoptimize.
4566 __ and_(result_reg, 1);
4567 DeoptimizeIf(not_zero, instr->environment());
4568 }
4569 __ bind(&done);
4570 }
4571}
4572
4573
4574void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004575 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004576 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004577 DeoptimizeIf(not_zero, instr->environment());
4578}
4579
4580
4581void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
4582 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004583 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004584 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004585}
4586
4587
4588void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004589 Register input = ToRegister(instr->InputAt(0));
4590 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004591
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004592 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004593
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004594 if (instr->hydrogen()->is_interval_check()) {
4595 InstanceType first;
4596 InstanceType last;
4597 instr->hydrogen()->GetCheckInterval(&first, &last);
4598
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004599 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4600 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004601
4602 // If there is only one type in the interval check for equality.
4603 if (first == last) {
4604 DeoptimizeIf(not_equal, instr->environment());
4605 } else {
4606 DeoptimizeIf(below, instr->environment());
4607 // Omit check for the last type.
4608 if (last != LAST_TYPE) {
4609 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4610 static_cast<int8_t>(last));
4611 DeoptimizeIf(above, instr->environment());
4612 }
4613 }
4614 } else {
4615 uint8_t mask;
4616 uint8_t tag;
4617 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4618
4619 if (IsPowerOf2(mask)) {
4620 ASSERT(tag == 0 || IsPowerOf2(tag));
4621 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
4622 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4623 } else {
4624 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4625 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004626 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004627 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004628 }
4629 }
4630}
4631
4632
4633void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004634 Handle<JSFunction> target = instr->hydrogen()->target();
4635 if (isolate()->heap()->InNewSpace(*target)) {
4636 Register reg = ToRegister(instr->value());
4637 Handle<JSGlobalPropertyCell> cell =
4638 isolate()->factory()->NewJSGlobalPropertyCell(target);
4639 __ cmp(reg, Operand::Cell(cell));
4640 } else {
4641 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004642 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004643 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004644 DeoptimizeIf(not_equal, instr->environment());
4645}
4646
4647
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004648void LCodeGen::DoCheckMapCommon(Register reg,
4649 Handle<Map> map,
4650 CompareMapMode mode,
4651 LEnvironment* env) {
4652 Label success;
4653 __ CompareMap(reg, map, &success, mode);
4654 DeoptimizeIf(not_equal, env);
4655 __ bind(&success);
4656}
4657
4658
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004659void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004660 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004661 ASSERT(input->IsRegister());
4662 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004663
4664 Label success;
4665 SmallMapList* map_set = instr->hydrogen()->map_set();
4666 for (int i = 0; i < map_set->length() - 1; i++) {
4667 Handle<Map> map = map_set->at(i);
4668 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
4669 __ j(equal, &success);
4670 }
4671 Handle<Map> map = map_set->last();
4672 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
4673 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004674}
4675
4676
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004677void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4678 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4679 Register result_reg = ToRegister(instr->result());
4680 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4681}
4682
4683
4684void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4685 ASSERT(instr->unclamped()->Equals(instr->result()));
4686 Register value_reg = ToRegister(instr->result());
4687 __ ClampUint8(value_reg);
4688}
4689
4690
4691void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4692 ASSERT(instr->unclamped()->Equals(instr->result()));
4693 Register input_reg = ToRegister(instr->unclamped());
4694 Label is_smi, done, heap_number;
4695
4696 __ JumpIfSmi(input_reg, &is_smi);
4697
4698 // Check for heap number
4699 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4700 factory()->heap_number_map());
4701 __ j(equal, &heap_number, Label::kNear);
4702
4703 // Check for undefined. Undefined is converted to zero for clamping
4704 // conversions.
4705 __ cmp(input_reg, factory()->undefined_value());
4706 DeoptimizeIf(not_equal, instr->environment());
4707 __ mov(input_reg, 0);
4708 __ jmp(&done, Label::kNear);
4709
4710 // Heap number
4711 __ bind(&heap_number);
4712 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4713 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4714 __ jmp(&done, Label::kNear);
4715
4716 // smi
4717 __ bind(&is_smi);
4718 __ SmiUntag(input_reg);
4719 __ ClampUint8(input_reg);
4720
4721 __ bind(&done);
4722}
4723
4724
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004725void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004726 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004727
4728 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004729 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004730
4731 // Load prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004732 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004733
4734 // Check prototype maps up to the holder.
4735 while (!current_prototype.is_identical_to(holder)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004736 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4737 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4738
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004739 current_prototype =
4740 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4741 // Load next prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004742 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004743 }
4744
4745 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004746 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4747 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004748}
4749
4750
ulan@chromium.org967e2702012-02-28 09:49:15 +00004751void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
4752 class DeferredAllocateObject: public LDeferredCode {
4753 public:
4754 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
4755 : LDeferredCode(codegen), instr_(instr) { }
4756 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
4757 virtual LInstruction* instr() { return instr_; }
4758 private:
4759 LAllocateObject* instr_;
4760 };
4761
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004762 DeferredAllocateObject* deferred =
4763 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004764
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004765 Register result = ToRegister(instr->result());
4766 Register scratch = ToRegister(instr->TempAt(0));
4767 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4768 Handle<Map> initial_map(constructor->initial_map());
4769 int instance_size = initial_map->instance_size();
4770 ASSERT(initial_map->pre_allocated_property_fields() +
4771 initial_map->unused_property_fields() -
4772 initial_map->inobject_properties() == 0);
4773
4774 // Allocate memory for the object. The initial map might change when
4775 // the constructor's prototype changes, but instance size and property
4776 // counts remain unchanged (if slack tracking finished).
4777 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
4778 __ AllocateInNewSpace(instance_size,
4779 result,
4780 no_reg,
4781 scratch,
4782 deferred->entry(),
4783 TAG_OBJECT);
4784
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004785 __ bind(deferred->exit());
4786 if (FLAG_debug_code) {
4787 Label is_in_new_space;
4788 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
4789 __ Abort("Allocated object is not in new-space");
4790 __ bind(&is_in_new_space);
4791 }
4792
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004793 // Load the initial map.
4794 Register map = scratch;
4795 __ LoadHeapObject(scratch, constructor);
4796 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
4797
4798 if (FLAG_debug_code) {
4799 __ AbortIfSmi(map);
4800 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
4801 instance_size >> kPointerSizeLog2);
4802 __ Assert(equal, "Unexpected instance size");
4803 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
4804 initial_map->pre_allocated_property_fields());
4805 __ Assert(equal, "Unexpected pre-allocated property fields count");
4806 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
4807 initial_map->unused_property_fields());
4808 __ Assert(equal, "Unexpected unused property fields count");
4809 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
4810 initial_map->inobject_properties());
4811 __ Assert(equal, "Unexpected in-object property fields count");
4812 }
4813
4814 // Initialize map and fields of the newly allocated object.
4815 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
4816 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
4817 __ mov(scratch, factory()->empty_fixed_array());
4818 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
4819 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
4820 if (initial_map->inobject_properties() != 0) {
4821 __ mov(scratch, factory()->undefined_value());
4822 for (int i = 0; i < initial_map->inobject_properties(); i++) {
4823 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
4824 __ mov(FieldOperand(result, property_offset), scratch);
4825 }
4826 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00004827}
4828
4829
4830void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
4831 Register result = ToRegister(instr->result());
4832 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004833 Handle<Map> initial_map(constructor->initial_map());
4834 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00004835
4836 // TODO(3095996): Get rid of this. For now, we need to make the
4837 // result register contain a valid pointer because it is already
4838 // contained in the register pointer map.
4839 __ Set(result, Immediate(0));
4840
4841 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004842 __ push(Immediate(Smi::FromInt(instance_size)));
4843 CallRuntimeFromDeferred(
4844 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00004845 __ StoreToSafepointRegisterSlot(result, eax);
4846}
4847
4848
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004849void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004850 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004851 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004852 ElementsKind boilerplate_elements_kind =
4853 instr->hydrogen()->boilerplate_elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004854
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004855 // Deopt if the array literal boilerplate ElementsKind is of a type different
4856 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004857 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
4858 if (CanTransitionToMoreGeneralFastElementsKind(
4859 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004860 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
4861 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
4862 // Load the map's "bit field 2". We only need the first byte,
4863 // but the following masking takes care of that anyway.
4864 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
4865 // Retrieve elements_kind from bit field 2.
4866 __ and_(ebx, Map::kElementsKindMask);
4867 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
4868 DeoptimizeIf(not_equal, instr->environment());
4869 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004870
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004871 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004872 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004873 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004874 // Boilerplate already exists, constant elements are never accessed.
4875 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004876 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004877
4878 // Pick the right runtime function or stub to call.
4879 int length = instr->hydrogen()->length();
4880 if (instr->hydrogen()->IsCopyOnWrite()) {
4881 ASSERT(instr->hydrogen()->depth() == 1);
4882 FastCloneShallowArrayStub::Mode mode =
4883 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4884 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004885 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004886 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004887 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004888 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004889 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004890 } else {
4891 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004892 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
4893 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4894 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004895 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004896 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004897 }
4898}
4899
4900
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004901void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
4902 Register result,
4903 Register source,
4904 int* offset) {
4905 ASSERT(!source.is(ecx));
4906 ASSERT(!result.is(ecx));
4907
4908 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004909 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004910 __ cmp(source, ecx);
4911 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00004912 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
4913 __ cmp(ecx, Handle<Map>(object->map()));
4914 __ Assert(equal, "Unexpected boilerplate map");
4915 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
4916 __ and_(ecx, Map::kElementsKindMask);
4917 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
4918 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004919 }
4920
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004921 // Only elements backing stores for non-COW arrays need to be copied.
4922 Handle<FixedArrayBase> elements(object->elements());
4923 bool has_elements = elements->length() > 0 &&
4924 elements->map() != isolate()->heap()->fixed_cow_array_map();
4925
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004926 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004927 // this object and its backing store.
4928 int object_offset = *offset;
4929 int object_size = object->map()->instance_size();
4930 int elements_offset = *offset + object_size;
4931 int elements_size = has_elements ? elements->Size() : 0;
4932 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004933
4934 // Copy object header.
4935 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004936 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004937 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004938 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004939 if (has_elements && i == JSObject::kElementsOffset) {
4940 __ lea(ecx, Operand(result, elements_offset));
4941 } else {
4942 __ mov(ecx, FieldOperand(source, i));
4943 }
4944 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004945 }
4946
4947 // Copy in-object properties.
4948 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004949 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004950 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
4951 if (value->IsJSObject()) {
4952 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4953 __ lea(ecx, Operand(result, *offset));
4954 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004955 __ LoadHeapObject(source, value_object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004956 EmitDeepCopy(value_object, result, source, offset);
4957 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004958 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004959 __ mov(FieldOperand(result, total_offset), ecx);
4960 } else {
4961 __ mov(FieldOperand(result, total_offset), Immediate(value));
4962 }
4963 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004964
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004965 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00004966 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004967 __ LoadHeapObject(source, elements);
4968 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
4969 __ mov(ecx, FieldOperand(source, i));
4970 __ mov(FieldOperand(result, elements_offset + i), ecx);
4971 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004972
danno@chromium.org88aa0582012-03-23 15:11:57 +00004973 // Copy elements backing store content.
4974 int elements_length = elements->length();
4975 if (elements->IsFixedDoubleArray()) {
4976 Handle<FixedDoubleArray> double_array =
4977 Handle<FixedDoubleArray>::cast(elements);
4978 for (int i = 0; i < elements_length; i++) {
4979 int64_t value = double_array->get_representation(i);
4980 int32_t value_low = value & 0xFFFFFFFF;
4981 int32_t value_high = value >> 32;
4982 int total_offset =
4983 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
4984 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
4985 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
4986 }
4987 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004988 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004989 for (int i = 0; i < elements_length; i++) {
4990 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004991 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00004992 if (value->IsJSObject()) {
4993 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
4994 __ lea(ecx, Operand(result, *offset));
4995 __ mov(FieldOperand(result, total_offset), ecx);
4996 __ LoadHeapObject(source, value_object);
4997 EmitDeepCopy(value_object, result, source, offset);
4998 } else if (value->IsHeapObject()) {
4999 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5000 __ mov(FieldOperand(result, total_offset), ecx);
5001 } else {
5002 __ mov(FieldOperand(result, total_offset), Immediate(value));
5003 }
5004 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005005 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005006 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005007 }
5008 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005009}
5010
5011
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005012void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005013 ASSERT(ToRegister(instr->context()).is(esi));
5014 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005015 ElementsKind boilerplate_elements_kind =
5016 instr->hydrogen()->boilerplate()->GetElementsKind();
5017
5018 // Deopt if the literal boilerplate ElementsKind is of a type different than
5019 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005020 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5021 if (CanTransitionToMoreGeneralFastElementsKind(
5022 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005023 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5024 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5025 // Load the map's "bit field 2". We only need the first byte,
5026 // but the following masking takes care of that anyway.
5027 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5028 // Retrieve elements_kind from bit field 2.
5029 __ and_(ecx, Map::kElementsKindMask);
5030 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5031 DeoptimizeIf(not_equal, instr->environment());
5032 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005033
5034 // Allocate all objects that are part of the literal in one big
5035 // allocation. This avoids multiple limit checks.
5036 Label allocated, runtime_allocate;
5037 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5038 __ jmp(&allocated);
5039
5040 __ bind(&runtime_allocate);
5041 __ push(Immediate(Smi::FromInt(size)));
5042 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5043
5044 __ bind(&allocated);
5045 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005046 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005047 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset);
5048 ASSERT_EQ(size, offset);
5049}
5050
5051
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005052void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005053 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005054 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005055 Handle<FixedArray> constant_properties =
5056 instr->hydrogen()->constant_properties();
5057
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005058 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005059 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005060 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005061 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 int flags = instr->hydrogen()->fast_elements()
5063 ? ObjectLiteral::kFastElements
5064 : ObjectLiteral::kNoFlags;
5065 flags |= instr->hydrogen()->has_function()
5066 ? ObjectLiteral::kHasFunction
5067 : ObjectLiteral::kNoFlags;
5068 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005069
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005070 // Pick the right runtime function or stub to call.
5071 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005072 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005073 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005074 } else if (flags != ObjectLiteral::kFastElements ||
5075 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005076 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005077 } else {
5078 FastCloneShallowObjectStub stub(properties_count);
5079 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005080 }
5081}
5082
5083
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
5085 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
5086 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005087 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005088}
5089
5090
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005091void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005092 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005093 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005094 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 // ecx = literals array.
5096 // ebx = regexp literal.
5097 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005098 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005099 int literal_offset =
5100 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5101 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005102 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005103 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005104 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005105
5106 // Create regexp literal using runtime function
5107 // Result will be in eax.
5108 __ push(ecx);
5109 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5110 __ push(Immediate(instr->hydrogen()->pattern()));
5111 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005112 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005113 __ mov(ebx, eax);
5114
5115 __ bind(&materialized);
5116 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5117 Label allocated, runtime_allocate;
5118 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5119 __ jmp(&allocated);
5120
5121 __ bind(&runtime_allocate);
5122 __ push(ebx);
5123 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005124 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005125 __ pop(ebx);
5126
5127 __ bind(&allocated);
5128 // Copy the content into the newly allocated memory.
5129 // (Unroll copy loop once for better throughput).
5130 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5131 __ mov(edx, FieldOperand(ebx, i));
5132 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5133 __ mov(FieldOperand(eax, i), edx);
5134 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5135 }
5136 if ((size % (2 * kPointerSize)) != 0) {
5137 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5138 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5139 }
5140}
5141
5142
5143void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005144 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 // Use the fast case closure allocation code that allocates in new
5146 // space for nested functions that don't need literals cloning.
5147 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005148 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005149 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005150 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005151 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005152 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005153 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005154 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005155 __ push(Immediate(shared_info));
5156 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005157 ? factory()->true_value()
5158 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005159 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005160 }
5161}
5162
5163
5164void LCodeGen::DoTypeof(LTypeof* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005165 LOperand* input = instr->InputAt(1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005166 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005167 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005168}
5169
5170
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005171void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00005172 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005173 int true_block = chunk_->LookupDestination(instr->true_block_id());
5174 int false_block = chunk_->LookupDestination(instr->false_block_id());
5175 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5176 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5177
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005178 Condition final_branch_condition =
5179 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5180 if (final_branch_condition != no_condition) {
5181 EmitBranch(true_block, false_block, final_branch_condition);
5182 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005183}
5184
5185
5186Condition LCodeGen::EmitTypeofIs(Label* true_label,
5187 Label* false_label,
5188 Register input,
5189 Handle<String> type_name) {
5190 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005192 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005193 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005195 final_branch_condition = equal;
5196
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005198 __ JumpIfSmi(input, false_label);
5199 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5200 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005201 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5202 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005203 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 } else if (type_name->Equals(heap()->boolean_symbol())) {
5206 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005207 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005209 final_branch_condition = equal;
5210
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005211 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
5212 __ cmp(input, factory()->null_value());
5213 final_branch_condition = equal;
5214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 } else if (type_name->Equals(heap()->undefined_symbol())) {
5216 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005217 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005218 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005219 // Check for undetectable objects => true.
5220 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5221 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5222 1 << Map::kIsUndetectable);
5223 final_branch_condition = not_zero;
5224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005226 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005227 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005228 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5229 __ j(equal, true_label);
5230 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5231 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005233 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005234 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005235 if (!FLAG_harmony_typeof) {
5236 __ cmp(input, factory()->null_value());
5237 __ j(equal, true_label);
5238 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005239 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005240 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005241 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5242 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005243 // Check for undetectable objects => false.
5244 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5245 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005246 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005247
5248 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005249 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005250 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005251 return final_branch_condition;
5252}
5253
5254
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005255void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
5256 Register temp = ToRegister(instr->TempAt(0));
5257 int true_block = chunk_->LookupDestination(instr->true_block_id());
5258 int false_block = chunk_->LookupDestination(instr->false_block_id());
5259
5260 EmitIsConstructCall(temp);
5261 EmitBranch(true_block, false_block, equal);
5262}
5263
5264
5265void LCodeGen::EmitIsConstructCall(Register temp) {
5266 // Get the frame pointer for the calling frame.
5267 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5268
5269 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005270 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005271 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5272 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005273 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005274 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5275
5276 // Check the marker in the calling frame.
5277 __ bind(&check_frame_marker);
5278 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5279 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5280}
5281
5282
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005283void LCodeGen::EnsureSpaceForLazyDeopt() {
5284 // Ensure that we have enough space after the previous lazy-bailout
5285 // instruction for patching the code here.
5286 int current_pc = masm()->pc_offset();
5287 int patch_size = Deoptimizer::patch_size();
5288 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5289 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005290 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005291 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005292 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005293}
5294
5295
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005296void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005297 EnsureSpaceForLazyDeopt();
5298 ASSERT(instr->HasEnvironment());
5299 LEnvironment* env = instr->environment();
5300 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5301 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005302}
5303
5304
5305void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5306 DeoptimizeIf(no_condition, instr->environment());
5307}
5308
5309
5310void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5311 LOperand* obj = instr->object();
5312 LOperand* key = instr->key();
5313 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005314 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005315 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005316 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005317 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005318 // Create safepoint generator that will also ensure enough space in the
5319 // reloc info for patching in deoptimization (since this is invoking a
5320 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005321 SafepointGenerator safepoint_generator(
5322 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005323 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005324 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005325}
5326
5327
ager@chromium.org04921a82011-06-27 13:21:41 +00005328void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005329 PushSafepointRegistersScope scope(this);
5330 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5331 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5332 RecordSafepointWithLazyDeopt(
5333 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5334 ASSERT(instr->HasEnvironment());
5335 LEnvironment* env = instr->environment();
5336 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005337}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005338
ager@chromium.org04921a82011-06-27 13:21:41 +00005339
5340void LCodeGen::DoStackCheck(LStackCheck* instr) {
5341 class DeferredStackCheck: public LDeferredCode {
5342 public:
5343 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5344 : LDeferredCode(codegen), instr_(instr) { }
5345 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005346 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005347 private:
5348 LStackCheck* instr_;
5349 };
5350
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005351 ASSERT(instr->HasEnvironment());
5352 LEnvironment* env = instr->environment();
5353 // There is no LLazyBailout instruction for stack-checks. We have to
5354 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005355 if (instr->hydrogen()->is_function_entry()) {
5356 // Perform stack overflow check.
5357 Label done;
5358 ExternalReference stack_limit =
5359 ExternalReference::address_of_stack_limit(isolate());
5360 __ cmp(esp, Operand::StaticVariable(stack_limit));
5361 __ j(above_equal, &done, Label::kNear);
5362
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005363 ASSERT(instr->context()->IsRegister());
5364 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00005365 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005366 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005367 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005368 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005369 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5370 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005371 } else {
5372 ASSERT(instr->hydrogen()->is_backwards_branch());
5373 // Perform stack overflow check if this goto needs it before jumping.
5374 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005375 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005376 ExternalReference stack_limit =
5377 ExternalReference::address_of_stack_limit(isolate());
5378 __ cmp(esp, Operand::StaticVariable(stack_limit));
5379 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005380 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005381 __ bind(instr->done_label());
5382 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005383 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5384 // Don't record a deoptimization index for the safepoint here.
5385 // This will be done explicitly when emitting call and the safepoint in
5386 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005387 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005388}
5389
5390
5391void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5392 // This is a pseudo-instruction that ensures that the environment here is
5393 // properly registered for deoptimization and records the assembler's PC
5394 // offset.
5395 LEnvironment* environment = instr->environment();
5396 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
5397 instr->SpilledDoubleRegisterArray());
5398
5399 // If the environment were already registered, we would have no way of
5400 // backpatching it with the spill slot operands.
5401 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005402 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005403 ASSERT(osr_pc_offset_ == -1);
5404 osr_pc_offset_ = masm()->pc_offset();
5405}
5406
5407
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005408void LCodeGen::DoIn(LIn* instr) {
5409 LOperand* obj = instr->object();
5410 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005411 EmitPushTaggedOperand(key);
5412 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005413 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005414 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005415 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005416 SafepointGenerator safepoint_generator(
5417 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005418 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005419}
5420
5421
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005422void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5423 __ cmp(eax, isolate()->factory()->undefined_value());
5424 DeoptimizeIf(equal, instr->environment());
5425
5426 __ cmp(eax, isolate()->factory()->null_value());
5427 DeoptimizeIf(equal, instr->environment());
5428
5429 __ test(eax, Immediate(kSmiTagMask));
5430 DeoptimizeIf(zero, instr->environment());
5431
5432 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5433 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5434 DeoptimizeIf(below_equal, instr->environment());
5435
5436 Label use_cache, call_runtime;
5437 __ CheckEnumCache(&call_runtime);
5438
5439 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5440 __ jmp(&use_cache, Label::kNear);
5441
5442 // Get the set of properties to enumerate.
5443 __ bind(&call_runtime);
5444 __ push(eax);
5445 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5446
5447 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5448 isolate()->factory()->meta_map());
5449 DeoptimizeIf(not_equal, instr->environment());
5450 __ bind(&use_cache);
5451}
5452
5453
5454void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5455 Register map = ToRegister(instr->map());
5456 Register result = ToRegister(instr->result());
5457 __ LoadInstanceDescriptors(map, result);
5458 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005459 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005460 __ mov(result,
5461 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
5462 __ test(result, result);
5463 DeoptimizeIf(equal, instr->environment());
5464}
5465
5466
5467void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5468 Register object = ToRegister(instr->value());
5469 __ cmp(ToRegister(instr->map()),
5470 FieldOperand(object, HeapObject::kMapOffset));
5471 DeoptimizeIf(not_equal, instr->environment());
5472}
5473
5474
5475void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5476 Register object = ToRegister(instr->object());
5477 Register index = ToRegister(instr->index());
5478
5479 Label out_of_object, done;
5480 __ cmp(index, Immediate(0));
5481 __ j(less, &out_of_object);
5482 __ mov(object, FieldOperand(object,
5483 index,
5484 times_half_pointer_size,
5485 JSObject::kHeaderSize));
5486 __ jmp(&done, Label::kNear);
5487
5488 __ bind(&out_of_object);
5489 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5490 __ neg(index);
5491 // Index is now equal to out of object property index plus 1.
5492 __ mov(object, FieldOperand(object,
5493 index,
5494 times_half_pointer_size,
5495 FixedArray::kHeaderSize - kPointerSize));
5496 __ bind(&done);
5497}
5498
5499
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005500#undef __
5501
5502} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005503
5504#endif // V8_TARGET_ARCH_IA32