blob: 388d4969dd67ea085861780be1e2f346e2872353 [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()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000143 Label begin;
144 __ bind(&begin);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000145 Label ok;
146 __ test(ecx, Operand(ecx));
147 __ j(zero, &ok, Label::kNear);
148 // +1 for return address.
149 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
150 __ mov(Operand(esp, receiver_offset),
151 Immediate(isolate()->factory()->undefined_value()));
152 __ bind(&ok);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000153 ASSERT(!FLAG_age_code ||
154 (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000155 }
156
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000157
158 if (dynamic_frame_alignment_) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000159 Label begin;
160 __ bind(&begin);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000161 // Move state of dynamic frame alignment into edx.
162 __ mov(edx, Immediate(kNoAlignmentPadding));
163
164 Label do_not_pad, align_loop;
165 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
166 // Align esp + 4 to a multiple of 2 * kPointerSize.
167 __ test(esp, Immediate(kPointerSize));
168 __ j(not_zero, &do_not_pad, Label::kNear);
169 __ push(Immediate(0));
170 __ mov(ebx, esp);
171 __ mov(edx, Immediate(kAlignmentPaddingPushed));
172 // Copy arguments, receiver, and return address.
173 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
174
175 __ bind(&align_loop);
176 __ mov(eax, Operand(ebx, 1 * kPointerSize));
177 __ mov(Operand(ebx, 0), eax);
178 __ add(Operand(ebx), Immediate(kPointerSize));
179 __ dec(ecx);
180 __ j(not_zero, &align_loop, Label::kNear);
181 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
182 __ bind(&do_not_pad);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000183 ASSERT(!FLAG_age_code ||
184 (kSizeOfOptimizedAlignStackPrologue ==
185 do_not_pad.pos() - begin.pos()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000186 }
187
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000188 __ push(ebp); // Caller's frame pointer.
189 __ mov(ebp, esp);
190 __ push(esi); // Callee's context.
191 __ push(edi); // Callee's JS function.
192
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000193 if (dynamic_frame_alignment_ && FLAG_debug_code) {
194 __ test(esp, Immediate(kPointerSize));
195 __ Assert(zero, "frame is expected to be aligned");
196 }
197
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000198 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000199 int slots = GetStackSlotCount();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000200 ASSERT_GE(slots, 1);
201 if (slots == 1) {
202 if (dynamic_frame_alignment_) {
203 __ push(edx);
204 } else {
205 __ push(Immediate(kNoAlignmentPadding));
206 }
207 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000208 if (FLAG_debug_code) {
209 __ mov(Operand(eax), Immediate(slots));
210 Label loop;
211 __ bind(&loop);
212 __ push(Immediate(kSlotsZapValue));
213 __ dec(eax);
214 __ j(not_zero, &loop);
215 } else {
216 __ sub(Operand(esp), Immediate(slots * kPointerSize));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000217 #ifdef _MSC_VER
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000218 // On windows, you may not access the stack more than one page below
219 // the most recently mapped page. To make the allocated area randomly
220 // accessible, we write to each page in turn (the value is irrelevant).
221 const int kPageSize = 4 * KB;
222 for (int offset = slots * kPointerSize - kPageSize;
223 offset > 0;
224 offset -= kPageSize) {
225 __ mov(Operand(esp, offset), eax);
226 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000227 #endif
228 }
229
230 // Store dynamic frame alignment state in the first local.
231 if (dynamic_frame_alignment_) {
232 __ mov(Operand(ebp,
233 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
234 edx);
235 } else {
236 __ mov(Operand(ebp,
237 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
238 Immediate(kNoAlignmentPadding));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000239 }
240 }
241
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000242 // Possibly allocate a local context.
243 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
244 if (heap_slots > 0) {
245 Comment(";;; Allocate local context");
246 // Argument to NewContext is the function, which is still in edi.
247 __ push(edi);
248 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
249 FastNewContextStub stub(heap_slots);
250 __ CallStub(&stub);
251 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000252 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000253 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000254 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000255 // Context is returned in both eax and esi. It replaces the context
256 // passed to us. It's saved in the stack and kept live in esi.
257 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
258
259 // Copy parameters into context if necessary.
260 int num_parameters = scope()->num_parameters();
261 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000262 Variable* var = scope()->parameter(i);
263 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000264 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
265 (num_parameters - 1 - i) * kPointerSize;
266 // Load parameter from stack.
267 __ mov(eax, Operand(ebp, parameter_offset));
268 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000269 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000270 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000271 // Update the write barrier. This clobbers eax and ebx.
272 __ RecordWriteContextSlot(esi,
273 context_offset,
274 eax,
275 ebx,
276 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000277 }
278 }
279 Comment(";;; End allocate local context");
280 }
281
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000282 // Trace the call.
283 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000284 // We have not executed any compiled code yet, so esi still holds the
285 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000286 __ CallRuntime(Runtime::kTraceEnter, 0);
287 }
288 return !is_aborted();
289}
290
291
292bool LCodeGen::GenerateBody() {
293 ASSERT(is_generating());
294 bool emit_instructions = true;
295 for (current_instruction_ = 0;
296 !is_aborted() && current_instruction_ < instructions_->length();
297 current_instruction_++) {
298 LInstruction* instr = instructions_->at(current_instruction_);
299 if (instr->IsLabel()) {
300 LLabel* label = LLabel::cast(instr);
301 emit_instructions = !label->HasReplacement();
302 }
303
304 if (emit_instructions) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000305 if (FLAG_code_comments) {
306 HValue* hydrogen = instr->hydrogen_value();
307 if (hydrogen != NULL) {
308 if (hydrogen->IsChange()) {
309 HValue* changed_value = HChange::cast(hydrogen)->value();
310 int use_id = 0;
311 const char* use_mnemo = "dead";
312 if (hydrogen->UseCount() >= 1) {
313 HValue* use_value = hydrogen->uses().value();
314 use_id = use_value->id();
315 use_mnemo = use_value->Mnemonic();
316 }
317 Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
318 current_instruction_, instr->Mnemonic(),
319 changed_value->id(), changed_value->Mnemonic(),
320 use_id, use_mnemo);
321 } else {
322 Comment(";;; @%d: %s. <#%d>", current_instruction_,
323 instr->Mnemonic(), hydrogen->id());
324 }
325 } else {
326 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
327 }
328 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329 instr->CompileToNative(this);
330 }
331 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000332 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000333 return !is_aborted();
334}
335
336
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000337bool LCodeGen::GenerateDeferredCode() {
338 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000339 if (deferred_.length() > 0) {
340 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
341 LDeferredCode* code = deferred_[i];
342 __ bind(code->entry());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000343 Comment(";;; Deferred code @%d: %s.",
344 code->instruction_index(),
345 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000346 code->Generate();
347 __ jmp(code->exit());
348 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000349 }
350
351 // Deferred code is the last part of the instruction sequence. Mark
352 // the generated code as done unless we bailed out.
353 if (!is_aborted()) status_ = DONE;
354 return !is_aborted();
355}
356
357
358bool LCodeGen::GenerateSafepointTable() {
359 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000360 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000361 return !is_aborted();
362}
363
364
365Register LCodeGen::ToRegister(int index) const {
366 return Register::FromAllocationIndex(index);
367}
368
369
370XMMRegister LCodeGen::ToDoubleRegister(int index) const {
371 return XMMRegister::FromAllocationIndex(index);
372}
373
374
375Register LCodeGen::ToRegister(LOperand* op) const {
376 ASSERT(op->IsRegister());
377 return ToRegister(op->index());
378}
379
380
381XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
382 ASSERT(op->IsDoubleRegister());
383 return ToDoubleRegister(op->index());
384}
385
386
387int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000388 HConstant* constant = chunk_->LookupConstant(op);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000389 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000390 ASSERT(constant->HasInteger32Value());
391 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000392}
393
394
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000395Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000396 HConstant* constant = chunk_->LookupConstant(op);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000397 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000398 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000399}
400
401
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000402double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000403 HConstant* constant = chunk_->LookupConstant(op);
404 ASSERT(constant->HasDoubleValue());
405 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000406}
407
408
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000409bool LCodeGen::IsInteger32(LConstantOperand* op) const {
410 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000411}
412
413
414Operand LCodeGen::ToOperand(LOperand* op) const {
415 if (op->IsRegister()) return Operand(ToRegister(op));
416 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
417 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
418 int index = op->index();
419 if (index >= 0) {
420 // Local or spill slot. Skip the frame pointer, function, and
421 // context in the fixed part of the frame.
422 return Operand(ebp, -(index + 3) * kPointerSize);
423 } else {
424 // Incoming parameter. Skip the return address.
425 return Operand(ebp, -(index - 1) * kPointerSize);
426 }
427}
428
429
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000430Operand LCodeGen::HighOperand(LOperand* op) {
431 ASSERT(op->IsDoubleStackSlot());
432 int index = op->index();
433 int offset = (index >= 0) ? index + 3 : index - 1;
434 return Operand(ebp, -offset * kPointerSize);
435}
436
437
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000438void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000439 Translation* translation,
440 int* arguments_index,
441 int* arguments_count) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000442 if (environment == NULL) return;
443
444 // The translation includes one command per value in the environment.
445 int translation_size = environment->values()->length();
446 // The output frame height does not include the parameters.
447 int height = translation_size - environment->parameter_count();
448
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000449 // Function parameters are arguments to the outermost environment. The
450 // arguments index points to the first element of a sequence of tagged
451 // values on the stack that represent the arguments. This needs to be
452 // kept in sync with the LArgumentsElements implementation.
453 *arguments_index = -environment->parameter_count();
454 *arguments_count = environment->parameter_count();
455
456 WriteTranslation(environment->outer(),
457 translation,
458 arguments_index,
459 arguments_count);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000460 int closure_id = *info()->closure() != *environment->closure()
461 ? DefineDeoptimizationLiteral(environment->closure())
462 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000463 switch (environment->frame_type()) {
464 case JS_FUNCTION:
465 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
466 break;
467 case JS_CONSTRUCT:
468 translation->BeginConstructStubFrame(closure_id, translation_size);
469 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000470 case JS_GETTER:
471 ASSERT(translation_size == 1);
472 ASSERT(height == 0);
473 translation->BeginGetterStubFrame(closure_id);
474 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000475 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000476 ASSERT(translation_size == 2);
477 ASSERT(height == 0);
478 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000479 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000480 case ARGUMENTS_ADAPTOR:
481 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
482 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000483 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000484
485 // Inlined frames which push their arguments cause the index to be
486 // bumped and another stack area to be used for materialization.
487 if (environment->entry() != NULL &&
488 environment->entry()->arguments_pushed()) {
489 *arguments_index = *arguments_index < 0
490 ? GetStackSlotCount()
491 : *arguments_index + *arguments_count;
492 *arguments_count = environment->entry()->arguments_count() + 1;
493 }
494
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000495 for (int i = 0; i < translation_size; ++i) {
496 LOperand* value = environment->values()->at(i);
497 // spilled_registers_ and spilled_double_registers_ are either
498 // both NULL or both set.
499 if (environment->spilled_registers() != NULL && value != NULL) {
500 if (value->IsRegister() &&
501 environment->spilled_registers()[value->index()] != NULL) {
502 translation->MarkDuplicate();
503 AddToTranslation(translation,
504 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000505 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000506 environment->HasUint32ValueAt(i),
507 *arguments_index,
508 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000509 } else if (
510 value->IsDoubleRegister() &&
511 environment->spilled_double_registers()[value->index()] != NULL) {
512 translation->MarkDuplicate();
513 AddToTranslation(
514 translation,
515 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000516 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000517 false,
518 *arguments_index,
519 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000520 }
521 }
522
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000523 AddToTranslation(translation,
524 value,
525 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000526 environment->HasUint32ValueAt(i),
527 *arguments_index,
528 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000529 }
530}
531
532
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533void LCodeGen::AddToTranslation(Translation* translation,
534 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000535 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000536 bool is_uint32,
537 int arguments_index,
538 int arguments_count) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 if (op == NULL) {
540 // TODO(twuerthinger): Introduce marker operands to indicate that this value
541 // is not present and must be reconstructed from the deoptimizer. Currently
542 // this is only used for the arguments object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000543 translation->StoreArgumentsObject(arguments_index, arguments_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000544 } else if (op->IsStackSlot()) {
545 if (is_tagged) {
546 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000547 } else if (is_uint32) {
548 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 } else {
550 translation->StoreInt32StackSlot(op->index());
551 }
552 } else if (op->IsDoubleStackSlot()) {
553 translation->StoreDoubleStackSlot(op->index());
554 } else if (op->IsArgument()) {
555 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000556 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000557 translation->StoreStackSlot(src_index);
558 } else if (op->IsRegister()) {
559 Register reg = ToRegister(op);
560 if (is_tagged) {
561 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000562 } else if (is_uint32) {
563 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000564 } else {
565 translation->StoreInt32Register(reg);
566 }
567 } else if (op->IsDoubleRegister()) {
568 XMMRegister reg = ToDoubleRegister(op);
569 translation->StoreDoubleRegister(reg);
570 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000571 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
572 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000573 translation->StoreLiteral(src_index);
574 } else {
575 UNREACHABLE();
576 }
577}
578
579
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000580void LCodeGen::CallCodeGeneric(Handle<Code> code,
581 RelocInfo::Mode mode,
582 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000583 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000584 ASSERT(instr != NULL);
585 LPointerMap* pointers = instr->pointer_map();
586 RecordPosition(pointers->position());
587 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000588 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000589
590 // Signal that we don't inline smi code before these stubs in the
591 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000592 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000593 code->kind() == Code::COMPARE_IC) {
594 __ nop();
595 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000596}
597
598
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000599void LCodeGen::CallCode(Handle<Code> code,
600 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000601 LInstruction* instr) {
602 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000603}
604
605
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000607 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000608 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000609 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000610 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000611 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 RecordPosition(pointers->position());
613
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000614 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000615
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000616 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000617}
618
619
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000620void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
621 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000622 LInstruction* instr,
623 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000624 if (context->IsRegister()) {
625 if (!ToRegister(context).is(esi)) {
626 __ mov(esi, ToRegister(context));
627 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000628 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000629 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000630 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000631 HConstant* constant =
632 chunk_->LookupConstant(LConstantOperand::cast(context));
633 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000634 } else {
635 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000636 }
637
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000638 __ CallRuntimeSaveDoubles(id);
639 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000640 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000641}
642
643
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000644void LCodeGen::RegisterEnvironmentForDeoptimization(
645 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 if (!environment->HasBeenRegistered()) {
647 // Physical stack frame layout:
648 // -x ............. -4 0 ..................................... y
649 // [incoming arguments] [spill slots] [pushed outgoing arguments]
650
651 // Layout of the environment:
652 // 0 ..................................................... size-1
653 // [parameters] [locals] [expression stack including arguments]
654
655 // Layout of the translation:
656 // 0 ........................................................ size - 1 + 4
657 // [expression stack including arguments] [locals] [4 words] [parameters]
658 // |>------------ translation_size ------------<|
659
660 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000661 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000662 int args_index = 0;
663 int args_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
665 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000666 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000667 ++jsframe_count;
668 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000669 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000670 Translation translation(&translations_, frame_count, jsframe_count, zone());
671 WriteTranslation(environment, &translation, &args_index, &args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000672 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000673 int pc_offset = masm()->pc_offset();
674 environment->Register(deoptimization_index,
675 translation.index(),
676 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000677 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678 }
679}
680
681
682void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000683 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000684 ASSERT(environment->HasBeenRegistered());
685 int id = environment->deoptimization_index();
686 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000687 if (entry == NULL) {
688 Abort("bailout was not prepared");
689 return;
690 }
691
692 if (FLAG_deopt_every_n_times != 0) {
693 Handle<SharedFunctionInfo> shared(info_->shared_info());
694 Label no_deopt;
695 __ pushfd();
696 __ push(eax);
697 __ push(ebx);
698 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000699 __ mov(eax,
700 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000701 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000702 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000703 if (FLAG_trap_on_deopt) __ int3();
704 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000705 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
706 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000707 __ pop(ebx);
708 __ pop(eax);
709 __ popfd();
710 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
711
712 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000713 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
714 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000715 __ pop(ebx);
716 __ pop(eax);
717 __ popfd();
718 }
719
720 if (cc == no_condition) {
721 if (FLAG_trap_on_deopt) __ int3();
722 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
723 } else {
724 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000725 Label done;
726 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000727 __ int3();
728 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
729 __ bind(&done);
730 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000731 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000732 }
733 }
734}
735
736
737void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
738 int length = deoptimizations_.length();
739 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000740 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000741 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000742
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000743 Handle<ByteArray> translations = translations_.CreateByteArray();
744 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000745 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
746
747 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000749 for (int i = 0; i < deoptimization_literals_.length(); i++) {
750 literals->set(i, *deoptimization_literals_[i]);
751 }
752 data->SetLiteralArray(*literals);
753
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000754 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
756
757 // Populate the deoptimization entries.
758 for (int i = 0; i < length; i++) {
759 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000760 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000761 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
762 data->SetArgumentsStackHeight(i,
763 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000764 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000765 }
766 code->set_deoptimization_data(*data);
767}
768
769
770int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
771 int result = deoptimization_literals_.length();
772 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
773 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
774 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000775 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776 return result;
777}
778
779
780void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
781 ASSERT(deoptimization_literals_.length() == 0);
782
783 const ZoneList<Handle<JSFunction> >* inlined_closures =
784 chunk()->inlined_closures();
785
786 for (int i = 0, length = inlined_closures->length();
787 i < length;
788 i++) {
789 DefineDeoptimizationLiteral(inlined_closures->at(i));
790 }
791
792 inlined_function_count_ = deoptimization_literals_.length();
793}
794
795
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000796void LCodeGen::RecordSafepointWithLazyDeopt(
797 LInstruction* instr, SafepointMode safepoint_mode) {
798 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
799 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
800 } else {
801 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
802 RecordSafepointWithRegisters(
803 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
804 }
805}
806
807
ager@chromium.org378b34e2011-01-28 08:04:38 +0000808void LCodeGen::RecordSafepoint(
809 LPointerMap* pointers,
810 Safepoint::Kind kind,
811 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000812 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000813 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000814 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000815 Safepoint safepoint =
816 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817 for (int i = 0; i < operands->length(); i++) {
818 LOperand* pointer = operands->at(i);
819 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000820 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000821 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000822 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000823 }
824 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000825}
826
827
828void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000829 Safepoint::DeoptMode mode) {
830 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000831}
832
833
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000834void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000835 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000836 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000837}
838
839
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000840void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
841 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000842 Safepoint::DeoptMode mode) {
843 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000844}
845
846
847void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000848 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000849 masm()->positions_recorder()->RecordPosition(position);
850}
851
852
853void LCodeGen::DoLabel(LLabel* label) {
854 if (label->is_loop_header()) {
855 Comment(";;; B%d - LOOP entry", label->block_id());
856 } else {
857 Comment(";;; B%d", label->block_id());
858 }
859 __ bind(label->label());
860 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000861 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000862}
863
864
865void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000866 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000867}
868
869
870void LCodeGen::DoGap(LGap* gap) {
871 for (int i = LGap::FIRST_INNER_POSITION;
872 i <= LGap::LAST_INNER_POSITION;
873 i++) {
874 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
875 LParallelMove* move = gap->GetParallelMove(inner_pos);
876 if (move != NULL) DoParallelMove(move);
877 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000878}
879
880
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000881void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
882 DoGap(instr);
883}
884
885
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000886void LCodeGen::DoParameter(LParameter* instr) {
887 // Nothing to do.
888}
889
890
891void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000892 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000893 ASSERT(ToRegister(instr->result()).is(eax));
894 switch (instr->hydrogen()->major_key()) {
895 case CodeStub::RegExpConstructResult: {
896 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000897 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000898 break;
899 }
900 case CodeStub::RegExpExec: {
901 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000902 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000903 break;
904 }
905 case CodeStub::SubString: {
906 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000907 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000908 break;
909 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000910 case CodeStub::NumberToString: {
911 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000912 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000913 break;
914 }
915 case CodeStub::StringAdd: {
916 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000917 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000918 break;
919 }
920 case CodeStub::StringCompare: {
921 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000922 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000923 break;
924 }
925 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000926 TranscendentalCacheStub stub(instr->transcendental_type(),
927 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000928 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000929 break;
930 }
931 default:
932 UNREACHABLE();
933 }
934}
935
936
937void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
938 // Nothing to do.
939}
940
941
942void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000943 if (instr->hydrogen()->HasPowerOf2Divisor()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000944 Register dividend = ToRegister(instr->left());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000945
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000946 int32_t divisor =
947 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000948
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000949 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000951 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000952 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000953 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000954 __ neg(dividend);
955 __ and_(dividend, divisor - 1);
956 __ neg(dividend);
957 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000958 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000959 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000960 } else {
961 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000962 }
963 __ bind(&positive_dividend);
964 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000965 __ bind(&done);
966 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000967 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000968 Register left_reg = ToRegister(instr->left());
969 Register right_reg = ToRegister(instr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000970 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000971
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000972 ASSERT(left_reg.is(eax));
973 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000974 ASSERT(!right_reg.is(eax));
975 ASSERT(!right_reg.is(edx));
976
977 // Check for x % 0.
978 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000979 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000980 DeoptimizeIf(zero, instr->environment());
981 }
982
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000983 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000984 __ j(zero, &remainder_eq_dividend, Label::kNear);
985 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000986
987 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000988 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000989 // The sign of the divisor doesn't matter.
990 __ neg(right_reg);
991
992 __ bind(&both_positive);
993 // If the dividend is smaller than the nonnegative
994 // divisor, the dividend is the result.
995 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000996 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000997
998 // Check if the divisor is a PowerOfTwo integer.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000999 Register scratch = ToRegister(instr->temp());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001000 __ mov(scratch, right_reg);
1001 __ sub(Operand(scratch), Immediate(1));
1002 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001003 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001004 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001005 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001006
1007 __ bind(&do_subtraction);
1008 const int kUnfolds = 3;
1009 // Try a few subtractions of the dividend.
1010 __ mov(scratch, left_reg);
1011 for (int i = 0; i < kUnfolds; i++) {
1012 // Reduce the dividend by the divisor.
1013 __ sub(left_reg, Operand(right_reg));
1014 // Check if the dividend is less than the divisor.
1015 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001016 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001017 }
1018 __ mov(left_reg, scratch);
1019
1020 // Slow case, using idiv instruction.
1021 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001022 // Sign extend to edx.
1023 __ cdq();
1024
1025 // Check for (0 % -x) that will produce negative zero.
1026 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001027 Label positive_left;
1028 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001029 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001030 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001031 __ idiv(right_reg);
1032
1033 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001034 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001035 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001036
1037 DeoptimizeIf(no_condition, instr->environment());
1038 __ bind(&positive_left);
1039 __ idiv(right_reg);
1040 __ bind(&done);
1041 } else {
1042 __ idiv(right_reg);
1043 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001044 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001045
1046 __ bind(&remainder_eq_dividend);
1047 __ mov(result_reg, left_reg);
1048
1049 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001050 }
1051}
1052
1053
1054void LCodeGen::DoDivI(LDivI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001055 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001056 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001057 ASSERT(ToRegister(instr->left()).is(eax));
1058 ASSERT(!ToRegister(instr->right()).is(eax));
1059 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001060
1061 Register left_reg = eax;
1062
1063 // Check for x / 0.
1064 Register right_reg = ToRegister(right);
1065 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1066 __ test(right_reg, ToOperand(right));
1067 DeoptimizeIf(zero, instr->environment());
1068 }
1069
1070 // Check for (0 / -x) that will produce negative zero.
1071 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001072 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001073 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001074 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075 __ test(right_reg, ToOperand(right));
1076 DeoptimizeIf(sign, instr->environment());
1077 __ bind(&left_not_zero);
1078 }
1079
1080 // Check for (-kMinInt / -1).
1081 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001082 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001083 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001084 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001085 __ cmp(right_reg, -1);
1086 DeoptimizeIf(zero, instr->environment());
1087 __ bind(&left_not_min_int);
1088 }
1089
1090 // Sign extend to edx.
1091 __ cdq();
1092 __ idiv(right_reg);
1093
1094 // Deoptimize if remainder is not 0.
1095 __ test(edx, Operand(edx));
1096 DeoptimizeIf(not_zero, instr->environment());
1097}
1098
1099
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001100void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001101 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001102
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001103 Register dividend = ToRegister(instr->left());
1104 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001105 Register result = ToRegister(instr->result());
1106
1107 switch (divisor) {
1108 case 0:
1109 DeoptimizeIf(no_condition, instr->environment());
1110 return;
1111
1112 case 1:
1113 __ Move(result, dividend);
1114 return;
1115
1116 case -1:
1117 __ Move(result, dividend);
1118 __ neg(result);
1119 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1120 DeoptimizeIf(zero, instr->environment());
1121 }
1122 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1123 DeoptimizeIf(overflow, instr->environment());
1124 }
1125 return;
1126 }
1127
1128 uint32_t divisor_abs = abs(divisor);
1129 if (IsPowerOf2(divisor_abs)) {
1130 int32_t power = WhichPowerOf2(divisor_abs);
1131 if (divisor < 0) {
1132 // Input[dividend] is clobbered.
1133 // The sequence is tedious because neg(dividend) might overflow.
1134 __ mov(result, dividend);
1135 __ sar(dividend, 31);
1136 __ neg(result);
1137 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1138 DeoptimizeIf(zero, instr->environment());
1139 }
1140 __ shl(dividend, 32 - power);
1141 __ sar(result, power);
1142 __ not_(dividend);
1143 // Clear result.sign if dividend.sign is set.
1144 __ and_(result, dividend);
1145 } else {
1146 __ Move(result, dividend);
1147 __ sar(result, power);
1148 }
1149 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001150 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001151 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001152 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001153
1154 // Find b which: 2^b < divisor_abs < 2^(b+1).
1155 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1156 unsigned shift = 32 + b; // Precision +1bit (effectively).
1157 double multiplier_f =
1158 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1159 int64_t multiplier;
1160 if (multiplier_f - floor(multiplier_f) < 0.5) {
1161 multiplier = static_cast<int64_t>(floor(multiplier_f));
1162 } else {
1163 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1164 }
1165 // The multiplier is a uint32.
1166 ASSERT(multiplier > 0 &&
1167 multiplier < (static_cast<int64_t>(1) << 32));
1168 __ mov(scratch, dividend);
1169 if (divisor < 0 &&
1170 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1171 __ test(dividend, dividend);
1172 DeoptimizeIf(zero, instr->environment());
1173 }
1174 __ mov(edx, static_cast<int32_t>(multiplier));
1175 __ imul(edx);
1176 if (static_cast<int32_t>(multiplier) < 0) {
1177 __ add(edx, scratch);
1178 }
1179 Register reg_lo = eax;
1180 Register reg_byte_scratch = scratch;
1181 if (!reg_byte_scratch.is_byte_register()) {
1182 __ xchg(reg_lo, reg_byte_scratch);
1183 reg_lo = scratch;
1184 reg_byte_scratch = eax;
1185 }
1186 if (divisor < 0) {
1187 __ xor_(reg_byte_scratch, reg_byte_scratch);
1188 __ cmp(reg_lo, 0x40000000);
1189 __ setcc(above, reg_byte_scratch);
1190 __ neg(edx);
1191 __ sub(edx, reg_byte_scratch);
1192 } else {
1193 __ xor_(reg_byte_scratch, reg_byte_scratch);
1194 __ cmp(reg_lo, 0xC0000000);
1195 __ setcc(above_equal, reg_byte_scratch);
1196 __ add(edx, reg_byte_scratch);
1197 }
1198 __ sar(edx, shift - 32);
1199 }
1200}
1201
1202
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001203void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001204 Register left = ToRegister(instr->left());
1205 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001206
1207 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001208 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001209 }
1210
1211 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001212 // Try strength reductions on the multiplication.
1213 // All replacement instructions are at most as long as the imul
1214 // and have better latency.
1215 int constant = ToInteger32(LConstantOperand::cast(right));
1216 if (constant == -1) {
1217 __ neg(left);
1218 } else if (constant == 0) {
1219 __ xor_(left, Operand(left));
1220 } else if (constant == 2) {
1221 __ add(left, Operand(left));
1222 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1223 // If we know that the multiplication can't overflow, it's safe to
1224 // use instructions that don't set the overflow flag for the
1225 // multiplication.
1226 switch (constant) {
1227 case 1:
1228 // Do nothing.
1229 break;
1230 case 3:
1231 __ lea(left, Operand(left, left, times_2, 0));
1232 break;
1233 case 4:
1234 __ shl(left, 2);
1235 break;
1236 case 5:
1237 __ lea(left, Operand(left, left, times_4, 0));
1238 break;
1239 case 8:
1240 __ shl(left, 3);
1241 break;
1242 case 9:
1243 __ lea(left, Operand(left, left, times_8, 0));
1244 break;
1245 case 16:
1246 __ shl(left, 4);
1247 break;
1248 default:
1249 __ imul(left, left, constant);
1250 break;
1251 }
1252 } else {
1253 __ imul(left, left, constant);
1254 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001255 } else {
1256 __ imul(left, ToOperand(right));
1257 }
1258
1259 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1260 DeoptimizeIf(overflow, instr->environment());
1261 }
1262
1263 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1264 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001265 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001266 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001267 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001269 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001270 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001271 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1272 __ cmp(ToRegister(instr->temp()), Immediate(0));
1273 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274 }
1275 } else {
1276 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001277 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001278 DeoptimizeIf(sign, instr->environment());
1279 }
1280 __ bind(&done);
1281 }
1282}
1283
1284
1285void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001286 LOperand* left = instr->left();
1287 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001288 ASSERT(left->Equals(instr->result()));
1289 ASSERT(left->IsRegister());
1290
1291 if (right->IsConstantOperand()) {
1292 int right_operand = ToInteger32(LConstantOperand::cast(right));
1293 switch (instr->op()) {
1294 case Token::BIT_AND:
1295 __ and_(ToRegister(left), right_operand);
1296 break;
1297 case Token::BIT_OR:
1298 __ or_(ToRegister(left), right_operand);
1299 break;
1300 case Token::BIT_XOR:
1301 __ xor_(ToRegister(left), right_operand);
1302 break;
1303 default:
1304 UNREACHABLE();
1305 break;
1306 }
1307 } else {
1308 switch (instr->op()) {
1309 case Token::BIT_AND:
1310 __ and_(ToRegister(left), ToOperand(right));
1311 break;
1312 case Token::BIT_OR:
1313 __ or_(ToRegister(left), ToOperand(right));
1314 break;
1315 case Token::BIT_XOR:
1316 __ xor_(ToRegister(left), ToOperand(right));
1317 break;
1318 default:
1319 UNREACHABLE();
1320 break;
1321 }
1322 }
1323}
1324
1325
1326void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001327 LOperand* left = instr->left();
1328 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001329 ASSERT(left->Equals(instr->result()));
1330 ASSERT(left->IsRegister());
1331 if (right->IsRegister()) {
1332 ASSERT(ToRegister(right).is(ecx));
1333
1334 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001335 case Token::ROR:
1336 __ ror_cl(ToRegister(left));
1337 if (instr->can_deopt()) {
1338 __ test(ToRegister(left), Immediate(0x80000000));
1339 DeoptimizeIf(not_zero, instr->environment());
1340 }
1341 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001342 case Token::SAR:
1343 __ sar_cl(ToRegister(left));
1344 break;
1345 case Token::SHR:
1346 __ shr_cl(ToRegister(left));
1347 if (instr->can_deopt()) {
1348 __ test(ToRegister(left), Immediate(0x80000000));
1349 DeoptimizeIf(not_zero, instr->environment());
1350 }
1351 break;
1352 case Token::SHL:
1353 __ shl_cl(ToRegister(left));
1354 break;
1355 default:
1356 UNREACHABLE();
1357 break;
1358 }
1359 } else {
1360 int value = ToInteger32(LConstantOperand::cast(right));
1361 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1362 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001363 case Token::ROR:
1364 if (shift_count == 0 && instr->can_deopt()) {
1365 __ test(ToRegister(left), Immediate(0x80000000));
1366 DeoptimizeIf(not_zero, instr->environment());
1367 } else {
1368 __ ror(ToRegister(left), shift_count);
1369 }
1370 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001371 case Token::SAR:
1372 if (shift_count != 0) {
1373 __ sar(ToRegister(left), shift_count);
1374 }
1375 break;
1376 case Token::SHR:
1377 if (shift_count == 0 && instr->can_deopt()) {
1378 __ test(ToRegister(left), Immediate(0x80000000));
1379 DeoptimizeIf(not_zero, instr->environment());
1380 } else {
1381 __ shr(ToRegister(left), shift_count);
1382 }
1383 break;
1384 case Token::SHL:
1385 if (shift_count != 0) {
1386 __ shl(ToRegister(left), shift_count);
1387 }
1388 break;
1389 default:
1390 UNREACHABLE();
1391 break;
1392 }
1393 }
1394}
1395
1396
1397void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001398 LOperand* left = instr->left();
1399 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001400 ASSERT(left->Equals(instr->result()));
1401
1402 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001403 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001404 } else {
1405 __ sub(ToRegister(left), ToOperand(right));
1406 }
1407 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1408 DeoptimizeIf(overflow, instr->environment());
1409 }
1410}
1411
1412
1413void LCodeGen::DoConstantI(LConstantI* instr) {
1414 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001415 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001416}
1417
1418
1419void LCodeGen::DoConstantD(LConstantD* instr) {
1420 ASSERT(instr->result()->IsDoubleRegister());
1421 XMMRegister res = ToDoubleRegister(instr->result());
1422 double v = instr->value();
1423 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1424 // do so if the constant is -0.0.
1425 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001426 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001427 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001428 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001429 uint64_t int_val = BitCast<uint64_t, double>(v);
1430 int32_t lower = static_cast<int32_t>(int_val);
1431 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001432 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001433 CpuFeatures::Scope scope(SSE4_1);
1434 if (lower != 0) {
1435 __ Set(temp, Immediate(lower));
1436 __ movd(res, Operand(temp));
1437 __ Set(temp, Immediate(upper));
1438 __ pinsrd(res, Operand(temp), 1);
1439 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001440 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001441 __ Set(temp, Immediate(upper));
1442 __ pinsrd(res, Operand(temp), 1);
1443 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001444 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001445 __ Set(temp, Immediate(upper));
1446 __ movd(res, Operand(temp));
1447 __ psllq(res, 32);
1448 if (lower != 0) {
1449 __ Set(temp, Immediate(lower));
1450 __ movd(xmm0, Operand(temp));
1451 __ por(res, xmm0);
1452 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001453 }
1454 }
1455}
1456
1457
1458void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001459 Register reg = ToRegister(instr->result());
1460 Handle<Object> handle = instr->value();
1461 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001462 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 } else {
1464 __ Set(reg, Immediate(handle));
1465 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001466}
1467
1468
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001469void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001470 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001471 Register array = ToRegister(instr->value());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001472 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1473}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001474
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001475
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001476void LCodeGen::DoFixedArrayBaseLength(
1477 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001478 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001479 Register array = ToRegister(instr->value());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001480 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001481}
1482
1483
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001484void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1485 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001486 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001487 __ EnumLength(result, map);
1488}
1489
1490
whesse@chromium.org7b260152011-06-20 15:33:18 +00001491void LCodeGen::DoElementsKind(LElementsKind* instr) {
1492 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001493 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001494
1495 // Load map into |result|.
1496 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1497 // Load the map's "bit field 2" into |result|. We only need the first byte,
1498 // but the following masking takes care of that anyway.
1499 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1500 // Retrieve elements_kind from bit field 2.
1501 __ and_(result, Map::kElementsKindMask);
1502 __ shr(result, Map::kElementsKindShift);
1503}
1504
1505
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001507 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001508 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001509 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001510 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001511
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001512 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001513 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001514 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001515
1516 // If the object is not a value type, return the object.
1517 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001518 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001519 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1520
1521 __ bind(&done);
1522}
1523
1524
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001525void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001526 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001527 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001528 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001529 Smi* index = instr->index();
1530 Label runtime, done;
1531 ASSERT(object.is(result));
1532 ASSERT(object.is(eax));
1533
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001534 __ test(object, Immediate(kSmiTagMask));
1535 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001536 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001537 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001538
1539 if (index->value() == 0) {
1540 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1541 } else {
1542 if (index->value() < JSDate::kFirstUncachedField) {
1543 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1544 __ mov(scratch, Operand::StaticVariable(stamp));
1545 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1546 __ j(not_equal, &runtime, Label::kNear);
1547 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1548 kPointerSize * index->value()));
1549 __ jmp(&done);
1550 }
1551 __ bind(&runtime);
1552 __ PrepareCallCFunction(2, scratch);
1553 __ mov(Operand(esp, 0), object);
1554 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1555 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1556 __ bind(&done);
1557 }
1558}
1559
1560
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001561void LCodeGen::DoBitNotI(LBitNotI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001562 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001563 ASSERT(input->Equals(instr->result()));
1564 __ not_(ToRegister(input));
1565}
1566
1567
1568void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001569 __ push(ToOperand(instr->value()));
1570 ASSERT(ToRegister(instr->context()).is(esi));
1571 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001572
1573 if (FLAG_debug_code) {
1574 Comment("Unreachable code.");
1575 __ int3();
1576 }
1577}
1578
1579
1580void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001581 LOperand* left = instr->left();
1582 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 ASSERT(left->Equals(instr->result()));
1584
1585 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001586 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001587 } else {
1588 __ add(ToRegister(left), ToOperand(right));
1589 }
1590
1591 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1592 DeoptimizeIf(overflow, instr->environment());
1593 }
1594}
1595
1596
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001597void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001598 LOperand* left = instr->left();
1599 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001600 ASSERT(left->Equals(instr->result()));
1601 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1602 if (instr->hydrogen()->representation().IsInteger32()) {
1603 Label return_left;
1604 Condition condition = (operation == HMathMinMax::kMathMin)
1605 ? less_equal
1606 : greater_equal;
1607 if (right->IsConstantOperand()) {
1608 Operand left_op = ToOperand(left);
1609 Immediate right_imm = ToInteger32Immediate(right);
1610 __ cmp(left_op, right_imm);
1611 __ j(condition, &return_left, Label::kNear);
1612 __ mov(left_op, right_imm);
1613 } else {
1614 Register left_reg = ToRegister(left);
1615 Operand right_op = ToOperand(right);
1616 __ cmp(left_reg, right_op);
1617 __ j(condition, &return_left, Label::kNear);
1618 __ mov(left_reg, right_op);
1619 }
1620 __ bind(&return_left);
1621 } else {
1622 ASSERT(instr->hydrogen()->representation().IsDouble());
1623 Label check_nan_left, check_zero, return_left, return_right;
1624 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1625 XMMRegister left_reg = ToDoubleRegister(left);
1626 XMMRegister right_reg = ToDoubleRegister(right);
1627 __ ucomisd(left_reg, right_reg);
1628 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1629 __ j(equal, &check_zero, Label::kNear); // left == right.
1630 __ j(condition, &return_left, Label::kNear);
1631 __ jmp(&return_right, Label::kNear);
1632
1633 __ bind(&check_zero);
1634 XMMRegister xmm_scratch = xmm0;
1635 __ xorps(xmm_scratch, xmm_scratch);
1636 __ ucomisd(left_reg, xmm_scratch);
1637 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1638 // At this point, both left and right are either 0 or -0.
1639 if (operation == HMathMinMax::kMathMin) {
1640 __ orpd(left_reg, right_reg);
1641 } else {
1642 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1643 __ addsd(left_reg, right_reg);
1644 }
1645 __ jmp(&return_left, Label::kNear);
1646
1647 __ bind(&check_nan_left);
1648 __ ucomisd(left_reg, left_reg); // NaN check.
1649 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1650 __ bind(&return_right);
1651 __ movsd(left_reg, right_reg);
1652
1653 __ bind(&return_left);
1654 }
1655}
1656
1657
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001658void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001659 XMMRegister left = ToDoubleRegister(instr->left());
1660 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001661 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001662 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001663 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001664 switch (instr->op()) {
1665 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001666 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001667 break;
1668 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001669 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001670 break;
1671 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001672 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001673 break;
1674 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001675 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001676 break;
1677 case Token::MOD: {
1678 // Pass two doubles as arguments on the stack.
1679 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001680 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1681 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 __ CallCFunction(
1683 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1684 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685
1686 // Return value is in st(0) on ia32.
1687 // Store it into the (fixed) result register.
1688 __ sub(Operand(esp), Immediate(kDoubleSize));
1689 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001690 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001691 __ add(Operand(esp), Immediate(kDoubleSize));
1692 break;
1693 }
1694 default:
1695 UNREACHABLE();
1696 break;
1697 }
1698}
1699
1700
1701void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001702 ASSERT(ToRegister(instr->context()).is(esi));
1703 ASSERT(ToRegister(instr->left()).is(edx));
1704 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001705 ASSERT(ToRegister(instr->result()).is(eax));
1706
danno@chromium.org40cb8782011-05-25 07:58:50 +00001707 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001708 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001709 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001710}
1711
1712
1713int LCodeGen::GetNextEmittedBlock(int block) {
1714 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1715 LLabel* label = chunk_->GetLabel(i);
1716 if (!label->HasReplacement()) return i;
1717 }
1718 return -1;
1719}
1720
1721
1722void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1723 int next_block = GetNextEmittedBlock(current_block_);
1724 right_block = chunk_->LookupDestination(right_block);
1725 left_block = chunk_->LookupDestination(left_block);
1726
1727 if (right_block == left_block) {
1728 EmitGoto(left_block);
1729 } else if (left_block == next_block) {
1730 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1731 } else if (right_block == next_block) {
1732 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1733 } else {
1734 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1735 __ jmp(chunk_->GetAssemblyLabel(right_block));
1736 }
1737}
1738
1739
1740void LCodeGen::DoBranch(LBranch* instr) {
1741 int true_block = chunk_->LookupDestination(instr->true_block_id());
1742 int false_block = chunk_->LookupDestination(instr->false_block_id());
1743
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001744 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001745 if (r.IsInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001746 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001747 __ test(reg, Operand(reg));
1748 EmitBranch(true_block, false_block, not_zero);
1749 } else if (r.IsDouble()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001750 XMMRegister reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001751 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001752 __ ucomisd(reg, xmm0);
1753 EmitBranch(true_block, false_block, not_equal);
1754 } else {
1755 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001756 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001757 HType type = instr->hydrogen()->value()->type();
1758 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001760 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001761 } else if (type.IsSmi()) {
1762 __ test(reg, Operand(reg));
1763 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001764 } else {
1765 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1766 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1767
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001768 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1769 // Avoid deopts in the case where we've never executed this path before.
1770 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001771
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001772 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1773 // undefined -> false.
1774 __ cmp(reg, factory()->undefined_value());
1775 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001776 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001777 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1778 // true -> true.
1779 __ cmp(reg, factory()->true_value());
1780 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001781 // false -> false.
1782 __ cmp(reg, factory()->false_value());
1783 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001784 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001785 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1786 // 'null' -> false.
1787 __ cmp(reg, factory()->null_value());
1788 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001789 }
1790
1791 if (expected.Contains(ToBooleanStub::SMI)) {
1792 // Smis: 0 -> false, all other -> true.
1793 __ test(reg, Operand(reg));
1794 __ j(equal, false_label);
1795 __ JumpIfSmi(reg, true_label);
1796 } else if (expected.NeedsMap()) {
1797 // If we need a map later and have a Smi -> deopt.
1798 __ test(reg, Immediate(kSmiTagMask));
1799 DeoptimizeIf(zero, instr->environment());
1800 }
1801
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001802 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001803 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001804 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001805 ASSERT(!map.is(reg));
1806 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001807
1808 if (expected.CanBeUndetectable()) {
1809 // Undetectable -> false.
1810 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1811 1 << Map::kIsUndetectable);
1812 __ j(not_zero, false_label);
1813 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001814 }
1815
1816 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1817 // spec object -> true.
1818 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1819 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001820 }
1821
1822 if (expected.Contains(ToBooleanStub::STRING)) {
1823 // String value -> false iff empty.
1824 Label not_string;
1825 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1826 __ j(above_equal, &not_string, Label::kNear);
1827 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1828 __ j(not_zero, true_label);
1829 __ jmp(false_label);
1830 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001831 }
1832
1833 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1834 // heap number -> false iff +0, -0, or NaN.
1835 Label not_heap_number;
1836 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1837 factory()->heap_number_map());
1838 __ j(not_equal, &not_heap_number, Label::kNear);
1839 __ fldz();
1840 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1841 __ FCmp();
1842 __ j(zero, false_label);
1843 __ jmp(true_label);
1844 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001845 }
1846
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001847 // We've seen something for the first time -> deopt.
1848 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001849 }
1850 }
1851}
1852
1853
ager@chromium.org04921a82011-06-27 13:21:41 +00001854void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001855 block = chunk_->LookupDestination(block);
1856 int next_block = GetNextEmittedBlock(current_block_);
1857 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001858 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001859 }
1860}
1861
1862
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001864 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001865}
1866
1867
1868Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1869 Condition cond = no_condition;
1870 switch (op) {
1871 case Token::EQ:
1872 case Token::EQ_STRICT:
1873 cond = equal;
1874 break;
1875 case Token::LT:
1876 cond = is_unsigned ? below : less;
1877 break;
1878 case Token::GT:
1879 cond = is_unsigned ? above : greater;
1880 break;
1881 case Token::LTE:
1882 cond = is_unsigned ? below_equal : less_equal;
1883 break;
1884 case Token::GTE:
1885 cond = is_unsigned ? above_equal : greater_equal;
1886 break;
1887 case Token::IN:
1888 case Token::INSTANCEOF:
1889 default:
1890 UNREACHABLE();
1891 }
1892 return cond;
1893}
1894
1895
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001897 LOperand* left = instr->left();
1898 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001899 int false_block = chunk_->LookupDestination(instr->false_block_id());
1900 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001902
1903 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1904 // We can statically evaluate the comparison.
1905 double left_val = ToDouble(LConstantOperand::cast(left));
1906 double right_val = ToDouble(LConstantOperand::cast(right));
1907 int next_block =
1908 EvalComparison(instr->op(), left_val, right_val) ? true_block
1909 : false_block;
1910 EmitGoto(next_block);
1911 } else {
1912 if (instr->is_double()) {
1913 // Don't base result on EFLAGS when a NaN is involved. Instead
1914 // jump to the false block.
1915 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1916 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1917 } else {
1918 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001919 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001920 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001921 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001922 // We transposed the operands. Reverse the condition.
1923 cc = ReverseCondition(cc);
1924 } else {
1925 __ cmp(ToRegister(left), ToOperand(right));
1926 }
1927 }
1928 EmitBranch(true_block, false_block, cc);
1929 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001930}
1931
1932
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001933void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001934 Register left = ToRegister(instr->left());
1935 Operand right = ToOperand(instr->right());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001936 int false_block = chunk_->LookupDestination(instr->false_block_id());
1937 int true_block = chunk_->LookupDestination(instr->true_block_id());
1938
1939 __ cmp(left, Operand(right));
1940 EmitBranch(true_block, false_block, equal);
1941}
1942
1943
whesse@chromium.org7b260152011-06-20 15:33:18 +00001944void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001945 Register left = ToRegister(instr->left());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001946 int true_block = chunk_->LookupDestination(instr->true_block_id());
1947 int false_block = chunk_->LookupDestination(instr->false_block_id());
1948
1949 __ cmp(left, instr->hydrogen()->right());
1950 EmitBranch(true_block, false_block, equal);
1951}
1952
1953
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001954void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001955 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001956 int false_block = chunk_->LookupDestination(instr->false_block_id());
1957
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001958 // If the expression is known to be untagged or a smi, then it's definitely
1959 // not null, and it can't be a an undetectable object.
1960 if (instr->hydrogen()->representation().IsSpecialization() ||
1961 instr->hydrogen()->type().IsSmi()) {
1962 EmitGoto(false_block);
1963 return;
1964 }
1965
1966 int true_block = chunk_->LookupDestination(instr->true_block_id());
1967 Handle<Object> nil_value = instr->nil() == kNullValue ?
1968 factory()->null_value() :
1969 factory()->undefined_value();
1970 __ cmp(reg, nil_value);
1971 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001972 EmitBranch(true_block, false_block, equal);
1973 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001974 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
1975 factory()->undefined_value() :
1976 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001977 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1978 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1979 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001980 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001982 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001983 // Check for undetectable objects by looking in the bit field in
1984 // the map. The object has already been smi checked.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001985 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1987 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1988 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1989 EmitBranch(true_block, false_block, not_zero);
1990 }
1991}
1992
1993
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001994Condition LCodeGen::EmitIsObject(Register input,
1995 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001996 Label* is_not_object,
1997 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001998 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002001 __ j(equal, is_object);
2002
2003 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2004 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002005 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2006 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002007 __ j(not_zero, is_not_object);
2008
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002009 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2010 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002011 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002012 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002013 return below_equal;
2014}
2015
2016
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002017void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002018 Register reg = ToRegister(instr->value());
2019 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002020
2021 int true_block = chunk_->LookupDestination(instr->true_block_id());
2022 int false_block = chunk_->LookupDestination(instr->false_block_id());
2023 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2024 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2025
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002026 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002027
2028 EmitBranch(true_block, false_block, true_cond);
2029}
2030
2031
erikcorry0ad885c2011-11-21 13:51:57 +00002032Condition LCodeGen::EmitIsString(Register input,
2033 Register temp1,
2034 Label* is_not_string) {
2035 __ JumpIfSmi(input, is_not_string);
2036
2037 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2038
2039 return cond;
2040}
2041
2042
2043void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002044 Register reg = ToRegister(instr->value());
2045 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002046
2047 int true_block = chunk_->LookupDestination(instr->true_block_id());
2048 int false_block = chunk_->LookupDestination(instr->false_block_id());
2049 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2050
2051 Condition true_cond = EmitIsString(reg, temp, false_label);
2052
2053 EmitBranch(true_block, false_block, true_cond);
2054}
2055
2056
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002057void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002058 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059
2060 int true_block = chunk_->LookupDestination(instr->true_block_id());
2061 int false_block = chunk_->LookupDestination(instr->false_block_id());
2062
2063 __ test(input, Immediate(kSmiTagMask));
2064 EmitBranch(true_block, false_block, zero);
2065}
2066
2067
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002068void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002069 Register input = ToRegister(instr->value());
2070 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002071
2072 int true_block = chunk_->LookupDestination(instr->true_block_id());
2073 int false_block = chunk_->LookupDestination(instr->false_block_id());
2074
2075 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002076 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002077 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2078 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2079 1 << Map::kIsUndetectable);
2080 EmitBranch(true_block, false_block, not_zero);
2081}
2082
2083
erikcorry0ad885c2011-11-21 13:51:57 +00002084static Condition ComputeCompareCondition(Token::Value op) {
2085 switch (op) {
2086 case Token::EQ_STRICT:
2087 case Token::EQ:
2088 return equal;
2089 case Token::LT:
2090 return less;
2091 case Token::GT:
2092 return greater;
2093 case Token::LTE:
2094 return less_equal;
2095 case Token::GTE:
2096 return greater_equal;
2097 default:
2098 UNREACHABLE();
2099 return no_condition;
2100 }
2101}
2102
2103
2104void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2105 Token::Value op = instr->op();
2106 int true_block = chunk_->LookupDestination(instr->true_block_id());
2107 int false_block = chunk_->LookupDestination(instr->false_block_id());
2108
2109 Handle<Code> ic = CompareIC::GetUninitialized(op);
2110 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2111
2112 Condition condition = ComputeCompareCondition(op);
2113 __ test(eax, Operand(eax));
2114
2115 EmitBranch(true_block, false_block, condition);
2116}
2117
2118
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002119static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002120 InstanceType from = instr->from();
2121 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122 if (from == FIRST_TYPE) return to;
2123 ASSERT(from == to || to == LAST_TYPE);
2124 return from;
2125}
2126
2127
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002128static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002129 InstanceType from = instr->from();
2130 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002131 if (from == to) return equal;
2132 if (to == LAST_TYPE) return above_equal;
2133 if (from == FIRST_TYPE) return below_equal;
2134 UNREACHABLE();
2135 return equal;
2136}
2137
2138
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002140 Register input = ToRegister(instr->value());
2141 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002142
2143 int true_block = chunk_->LookupDestination(instr->true_block_id());
2144 int false_block = chunk_->LookupDestination(instr->false_block_id());
2145
2146 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2147
whesse@chromium.org7b260152011-06-20 15:33:18 +00002148 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002149
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002150 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2151 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152}
2153
2154
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002155void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002156 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002157 Register result = ToRegister(instr->result());
2158
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002159 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002160
2161 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2162 __ IndexFromHash(result, result);
2163}
2164
2165
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002166void LCodeGen::DoHasCachedArrayIndexAndBranch(
2167 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002168 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169
2170 int true_block = chunk_->LookupDestination(instr->true_block_id());
2171 int false_block = chunk_->LookupDestination(instr->false_block_id());
2172
2173 __ test(FieldOperand(input, String::kHashFieldOffset),
2174 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002175 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002176}
2177
2178
2179// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002180// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181void LCodeGen::EmitClassOfTest(Label* is_true,
2182 Label* is_false,
2183 Handle<String>class_name,
2184 Register input,
2185 Register temp,
2186 Register temp2) {
2187 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002188 ASSERT(!input.is(temp2));
2189 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002190 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002191
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002192 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002193 // Assuming the following assertions, we can use the same compares to test
2194 // for both being a function type and being in the object type range.
2195 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2196 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2197 FIRST_SPEC_OBJECT_TYPE + 1);
2198 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2199 LAST_SPEC_OBJECT_TYPE - 1);
2200 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2201 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2202 __ j(below, is_false);
2203 __ j(equal, is_true);
2204 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2205 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002206 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002207 // Faster code path to avoid two compares: subtract lower bound from the
2208 // actual type and do a signed compare with the width of the type range.
2209 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002210 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002211 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002212 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2213 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002214 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002215 }
2216
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002217 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002218 // Check if the constructor in the map is a function.
2219 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002220 // Objects with a non-function constructor have class 'Object'.
2221 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
2222 if (class_name->IsEqualTo(CStrVector("Object"))) {
2223 __ j(not_equal, is_true);
2224 } else {
2225 __ j(not_equal, is_false);
2226 }
2227
2228 // temp now contains the constructor function. Grab the
2229 // instance class name from there.
2230 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2231 __ mov(temp, FieldOperand(temp,
2232 SharedFunctionInfo::kInstanceClassNameOffset));
2233 // The class name we are testing against is a symbol because it's a literal.
2234 // The name in the constructor is a symbol because of the way the context is
2235 // booted. This routine isn't expected to work for random API-created
2236 // classes and it doesn't have to because you can't access it with natives
2237 // syntax. Since both sides are symbols it is sufficient to use an identity
2238 // comparison.
2239 __ cmp(temp, class_name);
2240 // End with the answer in the z flag.
2241}
2242
2243
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002244void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002245 Register input = ToRegister(instr->value());
2246 Register temp = ToRegister(instr->temp());
2247 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002248
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002249 Handle<String> class_name = instr->hydrogen()->class_name();
2250
2251 int true_block = chunk_->LookupDestination(instr->true_block_id());
2252 int false_block = chunk_->LookupDestination(instr->false_block_id());
2253
2254 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2255 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2256
2257 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2258
2259 EmitBranch(true_block, false_block, equal);
2260}
2261
2262
2263void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002264 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002265 int true_block = instr->true_block_id();
2266 int false_block = instr->false_block_id();
2267
2268 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2269 EmitBranch(true_block, false_block, equal);
2270}
2271
2272
2273void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002274 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002275 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002276 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002277 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002278
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002279 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002280 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002281 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002283 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002284 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002286 __ bind(&done);
2287}
2288
2289
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002290void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2291 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2292 public:
2293 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2294 LInstanceOfKnownGlobal* instr)
2295 : LDeferredCode(codegen), instr_(instr) { }
2296 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002297 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002298 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002299 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002300 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002301 private:
2302 LInstanceOfKnownGlobal* instr_;
2303 Label map_check_;
2304 };
2305
2306 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002307 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002308
2309 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002310 Register object = ToRegister(instr->value());
2311 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002312
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002313 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002314 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002315
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002316 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002317 // hole value will be patched to the last map/result pair generated by the
2318 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002319 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002320 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002321 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2322 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002323 Handle<JSGlobalPropertyCell> cache_cell =
2324 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2325 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002326 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002327 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002328 __ jmp(&done);
2329
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002330 // The inlined call site cache did not match. Check for null and string
2331 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002332 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002333 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002334 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002335 __ j(equal, &false_result);
2336
2337 // String values are not instances of anything.
2338 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2339 __ j(is_string, &false_result);
2340
2341 // Go to the deferred code.
2342 __ jmp(deferred->entry());
2343
2344 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002345 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002346
2347 // Here result has either true or false. Deferred code also produces true or
2348 // false object.
2349 __ bind(deferred->exit());
2350 __ bind(&done);
2351}
2352
2353
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002354void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2355 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002356 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002357
2358 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2359 flags = static_cast<InstanceofStub::Flags>(
2360 flags | InstanceofStub::kArgsInRegisters);
2361 flags = static_cast<InstanceofStub::Flags>(
2362 flags | InstanceofStub::kCallSiteInlineCheck);
2363 flags = static_cast<InstanceofStub::Flags>(
2364 flags | InstanceofStub::kReturnTrueFalseObject);
2365 InstanceofStub stub(flags);
2366
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002367 // Get the temp register reserved by the instruction. This needs to be a
2368 // register which is pushed last by PushSafepointRegisters as top of the
2369 // stack is used to pass the offset to the location of the map check to
2370 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002371 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002372 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002373 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002374 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002375 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002376 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002377 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002378 CallCodeGeneric(stub.GetCode(),
2379 RelocInfo::CODE_TARGET,
2380 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002381 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002382 // Get the deoptimization index of the LLazyBailout-environment that
2383 // corresponds to this instruction.
2384 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002385 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2386
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002387 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002388 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002389}
2390
2391
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002392void LCodeGen::DoCmpT(LCmpT* instr) {
2393 Token::Value op = instr->op();
2394
2395 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002396 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002397
2398 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002399 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002400 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002401 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002402 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002403 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002404 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002405 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002406 __ bind(&done);
2407}
2408
2409
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002410void LCodeGen::DoReturn(LReturn* instr) {
2411 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002412 // Preserve the return value on the stack and rely on the runtime call
2413 // to return the value in the same register. We're leaving the code
2414 // managed by the register allocator and tearing down the frame, it's
2415 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002416 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002417 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002418 __ CallRuntime(Runtime::kTraceExit, 1);
2419 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002420 if (dynamic_frame_alignment_) {
2421 // Fetch the state of the dynamic frame alignment.
2422 __ mov(edx, Operand(ebp,
2423 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2424 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002425 __ mov(esp, ebp);
2426 __ pop(ebp);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002427 if (dynamic_frame_alignment_) {
2428 Label no_padding;
2429 __ cmp(edx, Immediate(kNoAlignmentPadding));
2430 __ j(equal, &no_padding);
2431 if (FLAG_debug_code) {
2432 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2433 Immediate(kAlignmentZapValue));
2434 __ Assert(equal, "expected alignment marker");
2435 }
2436 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2437 __ bind(&no_padding);
2438 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00002439 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002440}
2441
2442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002443void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002444 Register result = ToRegister(instr->result());
2445 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002446 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002447 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002448 DeoptimizeIf(equal, instr->environment());
2449 }
2450}
2451
2452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002453void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2454 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002455 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002456 ASSERT(ToRegister(instr->result()).is(eax));
2457
2458 __ mov(ecx, instr->name());
2459 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2460 RelocInfo::CODE_TARGET_CONTEXT;
2461 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002462 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002463}
2464
2465
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002466void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002467 Register value = ToRegister(instr->value());
2468 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002469
2470 // If the cell we are storing to contains the hole it could have
2471 // been deleted from the property dictionary. In that case, we need
2472 // to update the property details in the property dictionary to mark
2473 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002474 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002475 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002476 DeoptimizeIf(equal, instr->environment());
2477 }
2478
2479 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002480 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002481 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002482}
2483
2484
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002485void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2486 ASSERT(ToRegister(instr->context()).is(esi));
2487 ASSERT(ToRegister(instr->global_object()).is(edx));
2488 ASSERT(ToRegister(instr->value()).is(eax));
2489
2490 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002491 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002492 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2493 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002494 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002495}
2496
2497
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002498void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002499 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002500 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002501 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002502
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002503 if (instr->hydrogen()->RequiresHoleCheck()) {
2504 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002505 if (instr->hydrogen()->DeoptimizesOnHole()) {
2506 DeoptimizeIf(equal, instr->environment());
2507 } else {
2508 Label is_not_hole;
2509 __ j(not_equal, &is_not_hole, Label::kNear);
2510 __ mov(result, factory()->undefined_value());
2511 __ bind(&is_not_hole);
2512 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002513 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002514}
2515
2516
2517void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2518 Register context = ToRegister(instr->context());
2519 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002520
2521 Label skip_assignment;
2522
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002523 Operand target = ContextOperand(context, instr->slot_index());
2524 if (instr->hydrogen()->RequiresHoleCheck()) {
2525 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002526 if (instr->hydrogen()->DeoptimizesOnHole()) {
2527 DeoptimizeIf(equal, instr->environment());
2528 } else {
2529 __ j(not_equal, &skip_assignment, Label::kNear);
2530 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002531 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002532
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002533 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002534 if (instr->hydrogen()->NeedsWriteBarrier()) {
2535 HType type = instr->hydrogen()->value()->type();
2536 SmiCheck check_needed =
2537 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002538 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002539 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002540 __ RecordWriteContextSlot(context,
2541 offset,
2542 value,
2543 temp,
2544 kSaveFPRegs,
2545 EMIT_REMEMBERED_SET,
2546 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002547 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002548
2549 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002550}
2551
2552
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002553void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002554 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002555 Register result = ToRegister(instr->result());
2556 if (instr->hydrogen()->is_in_object()) {
2557 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2558 } else {
2559 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2560 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2561 }
2562}
2563
2564
lrn@chromium.org1c092762011-05-09 09:42:16 +00002565void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2566 Register object,
2567 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002568 Handle<String> name,
2569 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002570 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002571 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002572 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002573 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002574 int index = lookup.GetLocalFieldIndexFromMap(*type);
2575 int offset = index * kPointerSize;
2576 if (index < 0) {
2577 // Negative property indices are in-object properties, indexed
2578 // from the end of the fixed part of the object.
2579 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2580 } else {
2581 // Non-negative property indices are in the properties array.
2582 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2583 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2584 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002585 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002586 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002587 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002588 } else {
2589 // Negative lookup.
2590 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002591 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002592 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002593 while (*current != heap->null_value()) {
2594 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002595 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002596 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002597 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002598 current =
2599 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002600 }
2601 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002602 }
2603}
2604
2605
2606void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2607 ASSERT(!operand->IsDoubleRegister());
2608 if (operand->IsConstantOperand()) {
2609 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2610 if (object->IsSmi()) {
2611 __ Push(Handle<Smi>::cast(object));
2612 } else {
2613 __ PushHeapObject(Handle<HeapObject>::cast(object));
2614 }
2615 } else if (operand->IsRegister()) {
2616 __ push(ToRegister(operand));
2617 } else {
2618 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002619 }
2620}
2621
2622
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002623// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2624// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002625static bool CompactEmit(SmallMapList* list,
2626 Handle<String> name,
2627 int i,
2628 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002629 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002630 // If the map has ElementsKind transitions, we will generate map checks
2631 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002632 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002633 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002634 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002635 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002636}
2637
2638
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002639void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2640 Register object = ToRegister(instr->object());
2641 Register result = ToRegister(instr->result());
2642
2643 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002644 bool need_generic = instr->hydrogen()->need_generic();
2645
2646 if (map_count == 0 && !need_generic) {
2647 DeoptimizeIf(no_condition, instr->environment());
2648 return;
2649 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002650 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002651 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002652 bool all_are_compact = true;
2653 for (int i = 0; i < map_count; ++i) {
2654 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2655 all_are_compact = false;
2656 break;
2657 }
2658 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002659 for (int i = 0; i < map_count; ++i) {
2660 bool last = (i == map_count - 1);
2661 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002662 Label check_passed;
2663 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002664 if (last && !need_generic) {
2665 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002666 __ bind(&check_passed);
2667 EmitLoadFieldOrConstantFunction(
2668 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002669 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002670 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002671 bool compact = all_are_compact ? true :
2672 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
2673 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
2674 __ bind(&check_passed);
2675 EmitLoadFieldOrConstantFunction(
2676 result, object, map, name, instr->environment());
2677 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002678 __ bind(&next);
2679 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002680 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002681 if (need_generic) {
2682 __ mov(ecx, name);
2683 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2684 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2685 }
2686 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002687}
2688
2689
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002690void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002691 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002692 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002693 ASSERT(ToRegister(instr->result()).is(eax));
2694
2695 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002696 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002697 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002698}
2699
2700
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002701void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2702 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002703 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002704 Register result = ToRegister(instr->result());
2705
2706 // Check that the function really is a function.
2707 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2708 DeoptimizeIf(not_equal, instr->environment());
2709
2710 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002711 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002712 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2713 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002714 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002715
2716 // Get the prototype or initial map from the function.
2717 __ mov(result,
2718 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2719
2720 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002721 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002722 DeoptimizeIf(equal, instr->environment());
2723
2724 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002725 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002726 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002727 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002728
2729 // Get the prototype from the initial map.
2730 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002731 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002732
2733 // Non-instance prototype: Fetch prototype from constructor field
2734 // in the function's map.
2735 __ bind(&non_instance);
2736 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2737
2738 // All done.
2739 __ bind(&done);
2740}
2741
2742
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002743void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002744 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002745 Register input = ToRegister(instr->object());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002746 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002747 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002748 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002749 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002750 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002751 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002752 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002753 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002754 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002755 Register temp((result.is(eax)) ? ebx : eax);
2756 __ push(temp);
2757 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002758 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2759 __ and_(temp, Map::kElementsKindMask);
2760 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002761 __ cmp(temp, GetInitialFastElementsKind());
2762 __ j(less, &fail, Label::kNear);
2763 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
2764 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002765 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002766 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002767 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002768 __ j(less_equal, &ok, Label::kNear);
2769 __ bind(&fail);
2770 __ Abort("Check for fast or external elements failed.");
2771 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002772 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002773 __ bind(&done);
2774 }
2775}
2776
2777
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002778void LCodeGen::DoLoadExternalArrayPointer(
2779 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002780 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002781 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002782 __ mov(result, FieldOperand(input,
2783 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002784}
2785
2786
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002787void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2788 Register arguments = ToRegister(instr->arguments());
2789 Register length = ToRegister(instr->length());
2790 Operand index = ToOperand(instr->index());
2791 Register result = ToRegister(instr->result());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002792 // There are two words between the frame pointer and the last argument.
2793 // Subtracting from length accounts for one of them add one more.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002794 __ sub(length, index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002795 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2796}
2797
2798
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002799void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002800 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002801 LOperand* key = instr->key();
2802 if (!key->IsConstantOperand() &&
2803 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
2804 elements_kind)) {
2805 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002806 }
2807 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002808 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002809 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002810 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
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002863void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
2864 XMMRegister result = ToDoubleRegister(instr->result());
2865
2866 if (instr->hydrogen()->RequiresHoleCheck()) {
2867 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2868 sizeof(kHoleNanLower32);
2869 Operand hole_check_operand = BuildFastArrayOperand(
2870 instr->elements(), instr->key(),
2871 instr->hydrogen()->key()->representation(),
2872 FAST_DOUBLE_ELEMENTS,
2873 offset,
2874 instr->additional_index());
2875 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
2876 DeoptimizeIf(equal, instr->environment());
2877 }
2878
2879 Operand double_load_operand = BuildFastArrayOperand(
2880 instr->elements(),
2881 instr->key(),
2882 instr->hydrogen()->key()->representation(),
2883 FAST_DOUBLE_ELEMENTS,
2884 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
2885 instr->additional_index());
2886 __ movdbl(result, double_load_operand);
2887}
2888
2889
2890void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
2891 Register result = ToRegister(instr->result());
2892
2893 // Load the result.
2894 __ mov(result,
2895 BuildFastArrayOperand(instr->elements(),
2896 instr->key(),
2897 instr->hydrogen()->key()->representation(),
2898 FAST_ELEMENTS,
2899 FixedArray::kHeaderSize - kHeapObjectTag,
2900 instr->additional_index()));
2901
2902 // Check for the hole value.
2903 if (instr->hydrogen()->RequiresHoleCheck()) {
2904 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
2905 __ test(result, Immediate(kSmiTagMask));
2906 DeoptimizeIf(not_equal, instr->environment());
2907 } else {
2908 __ cmp(result, factory()->the_hole_value());
2909 DeoptimizeIf(equal, instr->environment());
2910 }
2911 }
2912}
2913
2914
2915void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
2916 if (instr->is_external()) {
2917 DoLoadKeyedExternalArray(instr);
2918 } else if (instr->hydrogen()->representation().IsDouble()) {
2919 DoLoadKeyedFixedDoubleArray(instr);
2920 } else {
2921 DoLoadKeyedFixedArray(instr);
2922 }
2923}
2924
2925
2926Operand LCodeGen::BuildFastArrayOperand(
2927 LOperand* elements_pointer,
2928 LOperand* key,
2929 Representation key_representation,
2930 ElementsKind elements_kind,
2931 uint32_t offset,
2932 uint32_t additional_index) {
2933 Register elements_pointer_reg = ToRegister(elements_pointer);
2934 int shift_size = ElementsKindToShiftSize(elements_kind);
2935 // Even though the HLoad/StoreKeyed instructions force the input
2936 // representation for the key to be an integer, the input gets replaced during
2937 // bound check elimination with the index argument to the bounds check, which
2938 // can be tagged, so that case must be handled here, too.
2939 if (key_representation.IsTagged() && (shift_size >= 1)) {
2940 shift_size -= kSmiTagSize;
2941 }
2942 if (key->IsConstantOperand()) {
2943 int constant_value = ToInteger32(LConstantOperand::cast(key));
2944 if (constant_value & 0xF0000000) {
2945 Abort("array index constant value too big");
2946 }
2947 return Operand(elements_pointer_reg,
2948 ((constant_value + additional_index) << shift_size)
2949 + offset);
2950 } else {
2951 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
2952 return Operand(elements_pointer_reg,
2953 ToRegister(key),
2954 scale_factor,
2955 offset + (additional_index << shift_size));
2956 }
2957}
2958
2959
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002960void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002961 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002962 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002963 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002964
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002965 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002966 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002967}
2968
2969
2970void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2971 Register result = ToRegister(instr->result());
2972
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002973 if (instr->hydrogen()->from_inlined()) {
2974 __ lea(result, Operand(esp, -2 * kPointerSize));
2975 } else {
2976 // Check for arguments adapter frame.
2977 Label done, adapted;
2978 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2979 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2980 __ cmp(Operand(result),
2981 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2982 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002983
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002984 // No arguments adaptor frame.
2985 __ mov(result, Operand(ebp));
2986 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002987
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002988 // Arguments adaptor frame present.
2989 __ bind(&adapted);
2990 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002991
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002992 // Result is the frame pointer for the frame if not adapted and for the real
2993 // frame below the adaptor frame if adapted.
2994 __ bind(&done);
2995 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002996}
2997
2998
2999void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003000 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003001 Register result = ToRegister(instr->result());
3002
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003003 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003004
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003005 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003006 __ cmp(ebp, elem);
3007 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003008 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003009
3010 // Arguments adaptor frame present. Get argument length from there.
3011 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3012 __ mov(result, Operand(result,
3013 ArgumentsAdaptorFrameConstants::kLengthOffset));
3014 __ SmiUntag(result);
3015
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003016 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003017 __ bind(&done);
3018}
3019
3020
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003021void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003022 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003023 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003024 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003025
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003026 // If the receiver is null or undefined, we have to pass the global
3027 // object as a receiver to normal functions. Values have to be
3028 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003029 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003030
3031 // Do not transform the receiver to object for strict mode
3032 // functions.
3033 __ mov(scratch,
3034 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3035 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3036 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003037 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003038
3039 // Do not transform the receiver to object for builtins.
3040 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3041 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003042 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003043
3044 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003045 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003046 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003047 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003048 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003049
3050 // The receiver should be a JS object.
3051 __ test(receiver, Immediate(kSmiTagMask));
3052 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003053 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003054 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003055 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003056
3057 __ bind(&global_object);
3058 // TODO(kmillikin): We have a hydrogen value for the global object. See
3059 // if it's better to use it than to explicitly fetch it from the context
3060 // here.
3061 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003062 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003063 __ mov(receiver,
3064 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003065 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003066}
3067
3068
3069void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3070 Register receiver = ToRegister(instr->receiver());
3071 Register function = ToRegister(instr->function());
3072 Register length = ToRegister(instr->length());
3073 Register elements = ToRegister(instr->elements());
3074 ASSERT(receiver.is(eax)); // Used for parameter count.
3075 ASSERT(function.is(edi)); // Required by InvokeFunction.
3076 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003077
3078 // Copy the arguments to this function possibly from the
3079 // adaptor frame below it.
3080 const uint32_t kArgumentsLimit = 1 * KB;
3081 __ cmp(length, kArgumentsLimit);
3082 DeoptimizeIf(above, instr->environment());
3083
3084 __ push(receiver);
3085 __ mov(receiver, length);
3086
3087 // Loop through the arguments pushing them onto the execution
3088 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003089 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003090 // length is a small non-negative integer, due to the test above.
3091 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003092 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003093 __ bind(&loop);
3094 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3095 __ dec(length);
3096 __ j(not_zero, &loop);
3097
3098 // Invoke the function.
3099 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003100 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003101 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003102 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003103 SafepointGenerator safepoint_generator(
3104 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003105 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003106 __ InvokeFunction(function, actual, CALL_FUNCTION,
3107 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003108}
3109
3110
3111void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003112 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003113 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003114}
3115
3116
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003117void LCodeGen::DoDrop(LDrop* instr) {
3118 __ Drop(instr->count());
3119}
3120
3121
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003122void LCodeGen::DoThisFunction(LThisFunction* instr) {
3123 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003124 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003125}
3126
3127
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003128void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003129 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003130 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003131}
3132
3133
3134void LCodeGen::DoOuterContext(LOuterContext* instr) {
3135 Register context = ToRegister(instr->context());
3136 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003137 __ mov(result,
3138 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003139}
3140
3141
yangguo@chromium.org56454712012-02-16 15:33:53 +00003142void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003143 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003144 __ push(esi); // The context is the first argument.
3145 __ push(Immediate(instr->hydrogen()->pairs()));
3146 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3147 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3148}
3149
3150
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003151void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3152 Register context = ToRegister(instr->context());
3153 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003154 __ mov(result,
3155 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003156}
3157
3158
3159void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003160 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003161 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003162 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003163}
3164
3165
3166void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3167 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003168 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003169 CallKind call_kind,
3170 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003171 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3172 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003173
3174 LPointerMap* pointers = instr->pointer_map();
3175 RecordPosition(pointers->position());
3176
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003177 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003178 if (edi_state == EDI_UNINITIALIZED) {
3179 __ LoadHeapObject(edi, function);
3180 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003181
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003182 // Change context.
3183 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003184
3185 // Set eax to arguments count if adaption is not needed. Assumes that eax
3186 // is available to write to at this point.
3187 if (!function->NeedsArgumentsAdaption()) {
3188 __ mov(eax, arity);
3189 }
3190
3191 // Invoke function directly.
3192 __ SetCallKind(ecx, call_kind);
3193 if (*function == *info()->closure()) {
3194 __ CallSelf();
3195 } else {
3196 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3197 }
3198 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3199 } else {
3200 // We need to adapt arguments.
3201 SafepointGenerator generator(
3202 this, pointers, Safepoint::kLazyDeopt);
3203 ParameterCount count(arity);
3204 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3205 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003206}
3207
3208
3209void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3210 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003211 CallKnownFunction(instr->function(),
3212 instr->arity(),
3213 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003214 CALL_AS_METHOD,
3215 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003216}
3217
3218
3219void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003220 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003221 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003222 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003223 DeoptimizeIf(not_equal, instr->environment());
3224
3225 Label done;
3226 Register tmp = input_reg.is(eax) ? ecx : eax;
3227 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3228
3229 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003230 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003231
3232 Label negative;
3233 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003234 // Check the sign of the argument. If the argument is positive, just
3235 // return it. We do not need to patch the stack since |input| and
3236 // |result| are the same register and |input| will be restored
3237 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003238 __ test(tmp, Immediate(HeapNumber::kSignMask));
3239 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003240 __ jmp(&done);
3241
3242 __ bind(&negative);
3243
3244 Label allocated, slow;
3245 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3246 __ jmp(&allocated);
3247
3248 // Slow case: Call the runtime system to do the number allocation.
3249 __ bind(&slow);
3250
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003251 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3252 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003253
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003254 // Set the pointer to the new heap number in tmp.
3255 if (!tmp.is(eax)) __ mov(tmp, eax);
3256
3257 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003258 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003259
3260 __ bind(&allocated);
3261 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3262 __ and_(tmp2, ~HeapNumber::kSignMask);
3263 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3264 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3265 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003266 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003267
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003268 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003269}
3270
3271
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003272void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003273 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003274 __ test(input_reg, Operand(input_reg));
3275 Label is_positive;
3276 __ j(not_sign, &is_positive);
3277 __ neg(input_reg);
3278 __ test(input_reg, Operand(input_reg));
3279 DeoptimizeIf(negative, instr->environment());
3280 __ bind(&is_positive);
3281}
3282
3283
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003284void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3285 // Class for deferred case.
3286 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3287 public:
3288 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3289 LUnaryMathOperation* instr)
3290 : LDeferredCode(codegen), instr_(instr) { }
3291 virtual void Generate() {
3292 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3293 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003294 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003295 private:
3296 LUnaryMathOperation* instr_;
3297 };
3298
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003299 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003300 Representation r = instr->hydrogen()->value()->representation();
3301
3302 if (r.IsDouble()) {
3303 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003304 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003305 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003306 __ subsd(scratch, input_reg);
3307 __ pand(input_reg, scratch);
3308 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003309 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003310 } else { // Tagged case.
3311 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003312 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003313 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003314 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003315 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003316 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003317 __ bind(deferred->exit());
3318 }
3319}
3320
3321
3322void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
3323 XMMRegister xmm_scratch = xmm0;
3324 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003325 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003326
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003327 if (CpuFeatures::IsSupported(SSE4_1)) {
3328 CpuFeatures::Scope scope(SSE4_1);
3329 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3330 // Deoptimize on negative zero.
3331 Label non_zero;
3332 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3333 __ ucomisd(input_reg, xmm_scratch);
3334 __ j(not_equal, &non_zero, Label::kNear);
3335 __ movmskpd(output_reg, input_reg);
3336 __ test(output_reg, Immediate(1));
3337 DeoptimizeIf(not_zero, instr->environment());
3338 __ bind(&non_zero);
3339 }
3340 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3341 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3342 // Overflow is signalled with minint.
3343 __ cmp(output_reg, 0x80000000u);
3344 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003345 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003346 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003347 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003348 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3349 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003350 DeoptimizeIf(parity_even, instr->environment());
3351 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003352
3353 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3354 // Check for negative zero.
3355 Label positive_sign;
3356 __ j(above, &positive_sign, Label::kNear);
3357 __ movmskpd(output_reg, input_reg);
3358 __ test(output_reg, Immediate(1));
3359 DeoptimizeIf(not_zero, instr->environment());
3360 __ Set(output_reg, Immediate(0));
3361 __ jmp(&done, Label::kNear);
3362 __ bind(&positive_sign);
3363 }
3364
3365 // Use truncating instruction (OK because input is positive).
3366 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003367 // Overflow is signalled with minint.
3368 __ cmp(output_reg, 0x80000000u);
3369 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003370 __ jmp(&done, Label::kNear);
3371
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003372 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003373 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003374 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003375 __ cvttsd2si(output_reg, Operand(input_reg));
3376 __ cvtsi2sd(xmm_scratch, output_reg);
3377 __ ucomisd(input_reg, xmm_scratch);
3378 __ j(equal, &done, Label::kNear);
3379 __ sub(output_reg, Immediate(1));
3380 DeoptimizeIf(overflow, instr->environment());
3381
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003382 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003384}
3385
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003386void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
3387 XMMRegister xmm_scratch = xmm0;
3388 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003389 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003390
danno@chromium.org160a7b02011-04-18 15:51:38 +00003391 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003392 // xmm_scratch = 0.5
3393 ExternalReference one_half = ExternalReference::address_of_one_half();
3394 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003395 __ ucomisd(xmm_scratch, input_reg);
3396 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003397 // xmm_scratch = input + 0.5
3398 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003399
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003400 // Compute Math.floor(value + 0.5).
3401 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003402 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003403
3404 // Overflow is signalled with minint.
3405 __ cmp(output_reg, 0x80000000u);
3406 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003407 __ jmp(&done);
3408
3409 __ bind(&below_half);
3410
3411 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3412 // we can ignore the difference between a result of -0 and +0.
3413 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3414 // If the sign is positive, we return +0.
3415 __ movmskpd(output_reg, input_reg);
3416 __ test(output_reg, Immediate(1));
3417 DeoptimizeIf(not_zero, instr->environment());
3418 } else {
3419 // If the input is >= -0.5, we return +0.
3420 __ mov(output_reg, Immediate(0xBF000000));
3421 __ movd(xmm_scratch, Operand(output_reg));
3422 __ cvtss2sd(xmm_scratch, xmm_scratch);
3423 __ ucomisd(input_reg, xmm_scratch);
3424 DeoptimizeIf(below, instr->environment());
3425 }
3426 __ Set(output_reg, Immediate(0));
3427 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003428}
3429
3430
3431void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003432 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003433 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3434 __ sqrtsd(input_reg, input_reg);
3435}
3436
3437
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003438void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003439 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003440 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003441 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003442 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003443
3444 // Note that according to ECMA-262 15.8.2.13:
3445 // Math.pow(-Infinity, 0.5) == Infinity
3446 // Math.sqrt(-Infinity) == NaN
3447 Label done, sqrt;
3448 // Check base for -Infinity. According to IEEE-754, single-precision
3449 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3450 __ mov(scratch, 0xFF800000);
3451 __ movd(xmm_scratch, scratch);
3452 __ cvtss2sd(xmm_scratch, xmm_scratch);
3453 __ ucomisd(input_reg, xmm_scratch);
3454 // Comparing -Infinity with NaN results in "unordered", which sets the
3455 // zero flag as if both were equal. However, it also sets the carry flag.
3456 __ j(not_equal, &sqrt, Label::kNear);
3457 __ j(carry, &sqrt, Label::kNear);
3458 // If input is -Infinity, return Infinity.
3459 __ xorps(input_reg, input_reg);
3460 __ subsd(input_reg, xmm_scratch);
3461 __ jmp(&done, Label::kNear);
3462
3463 // Square root.
3464 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003465 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003466 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003467 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003468 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003469}
3470
3471
3472void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003473 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003474 // Having marked this as a call, we can use any registers.
3475 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003476 ASSERT(!instr->right()->IsDoubleRegister() ||
3477 ToDoubleRegister(instr->right()).is(xmm1));
3478 ASSERT(!instr->right()->IsRegister() ||
3479 ToRegister(instr->right()).is(eax));
3480 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003481 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003483 if (exponent_type.IsTagged()) {
3484 Label no_deopt;
3485 __ JumpIfSmi(eax, &no_deopt);
3486 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003487 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003488 __ bind(&no_deopt);
3489 MathPowStub stub(MathPowStub::TAGGED);
3490 __ CallStub(&stub);
3491 } else if (exponent_type.IsInteger32()) {
3492 MathPowStub stub(MathPowStub::INTEGER);
3493 __ CallStub(&stub);
3494 } else {
3495 ASSERT(exponent_type.IsDouble());
3496 MathPowStub stub(MathPowStub::DOUBLE);
3497 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003498 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003499}
3500
3501
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003502void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003503 class DeferredDoRandom: public LDeferredCode {
3504 public:
3505 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3506 : LDeferredCode(codegen), instr_(instr) { }
3507 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3508 virtual LInstruction* instr() { return instr_; }
3509 private:
3510 LRandom* instr_;
3511 };
3512
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003513 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003514
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003515 // Having marked this instruction as a call we can use any
3516 // registers.
3517 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003518 ASSERT(ToRegister(instr->global_object()).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003519 // Assert that the register size is indeed the size of each seed.
3520 static const int kSeedSize = sizeof(uint32_t);
3521 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003522
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003523 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003524 static const int kRandomSeedOffset =
3525 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3526 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003527 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003528
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003529 // Load state[0].
3530 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3531 // If state[0] == 0, call runtime to initialize seeds.
3532 __ test(ecx, ecx);
3533 __ j(zero, deferred->entry());
3534 // Load state[1].
3535 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3536 // ecx: state[0]
3537 // eax: state[1]
3538
3539 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3540 __ movzx_w(edx, ecx);
3541 __ imul(edx, edx, 18273);
3542 __ shr(ecx, 16);
3543 __ add(ecx, edx);
3544 // Save state[0].
3545 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3546
3547 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3548 __ movzx_w(edx, eax);
3549 __ imul(edx, edx, 36969);
3550 __ shr(eax, 16);
3551 __ add(eax, edx);
3552 // Save state[1].
3553 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3554
3555 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3556 __ shl(ecx, 14);
3557 __ and_(eax, Immediate(0x3FFFF));
3558 __ add(eax, ecx);
3559
3560 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003561 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3562 // by computing:
3563 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3564 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3565 __ movd(xmm2, ebx);
3566 __ movd(xmm1, eax);
3567 __ cvtss2sd(xmm2, xmm2);
3568 __ xorps(xmm1, xmm2);
3569 __ subsd(xmm1, xmm2);
3570}
3571
3572
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003573void LCodeGen::DoDeferredRandom(LRandom* instr) {
3574 __ PrepareCallCFunction(1, ebx);
3575 __ mov(Operand(esp, 0), eax);
3576 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3577 // Return value is in eax.
3578}
3579
3580
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003581void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003582 ASSERT(instr->value()->Equals(instr->result()));
3583 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003584 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003585 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003586 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003587 __ j(above, &positive, Label::kNear);
3588 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003589 ExternalReference nan =
3590 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003591 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003592 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003593 __ bind(&zero);
3594 __ push(Immediate(0xFFF00000));
3595 __ push(Immediate(0));
3596 __ movdbl(input_reg, Operand(esp, 0));
3597 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003598 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003599 __ bind(&positive);
3600 __ fldln2();
3601 __ sub(Operand(esp), Immediate(kDoubleSize));
3602 __ movdbl(Operand(esp, 0), input_reg);
3603 __ fld_d(Operand(esp, 0));
3604 __ fyl2x();
3605 __ fstp_d(Operand(esp, 0));
3606 __ movdbl(input_reg, Operand(esp, 0));
3607 __ add(Operand(esp), Immediate(kDoubleSize));
3608 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003609}
3610
3611
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003612void LCodeGen::DoMathExp(LMathExp* instr) {
3613 XMMRegister input = ToDoubleRegister(instr->value());
3614 XMMRegister result = ToDoubleRegister(instr->result());
3615 Register temp1 = ToRegister(instr->temp1());
3616 Register temp2 = ToRegister(instr->temp2());
3617
3618 MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
3619}
3620
3621
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003622void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3623 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3624 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3625 TranscendentalCacheStub::UNTAGGED);
3626 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3627}
3628
3629
whesse@chromium.org023421e2010-12-21 12:19:12 +00003630void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3631 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3632 TranscendentalCacheStub stub(TranscendentalCache::COS,
3633 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003634 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003635}
3636
3637
3638void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3639 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3640 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3641 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003642 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003643}
3644
3645
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003646void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3647 switch (instr->op()) {
3648 case kMathAbs:
3649 DoMathAbs(instr);
3650 break;
3651 case kMathFloor:
3652 DoMathFloor(instr);
3653 break;
3654 case kMathRound:
3655 DoMathRound(instr);
3656 break;
3657 case kMathSqrt:
3658 DoMathSqrt(instr);
3659 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003660 case kMathCos:
3661 DoMathCos(instr);
3662 break;
3663 case kMathSin:
3664 DoMathSin(instr);
3665 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003666 case kMathTan:
3667 DoMathTan(instr);
3668 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003669 case kMathLog:
3670 DoMathLog(instr);
3671 break;
3672
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003673 default:
3674 UNREACHABLE();
3675 }
3676}
3677
3678
danno@chromium.org160a7b02011-04-18 15:51:38 +00003679void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3680 ASSERT(ToRegister(instr->context()).is(esi));
3681 ASSERT(ToRegister(instr->function()).is(edi));
3682 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003683
3684 if (instr->known_function().is_null()) {
3685 LPointerMap* pointers = instr->pointer_map();
3686 RecordPosition(pointers->position());
3687 SafepointGenerator generator(
3688 this, pointers, Safepoint::kLazyDeopt);
3689 ParameterCount count(instr->arity());
3690 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3691 } else {
3692 CallKnownFunction(instr->known_function(),
3693 instr->arity(),
3694 instr,
3695 CALL_AS_METHOD,
3696 EDI_CONTAINS_TARGET);
3697 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003698}
3699
3700
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003701void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003702 ASSERT(ToRegister(instr->context()).is(esi));
3703 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003704 ASSERT(ToRegister(instr->result()).is(eax));
3705
3706 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003707 Handle<Code> ic =
3708 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003709 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003710}
3711
3712
3713void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003714 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003715 ASSERT(ToRegister(instr->result()).is(eax));
3716
3717 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003718 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3719 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003720 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003721 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003722 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003723}
3724
3725
3726void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003727 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003728 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003729 ASSERT(ToRegister(instr->result()).is(eax));
3730
3731 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003732 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003733 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003734}
3735
3736
3737void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003738 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003739 ASSERT(ToRegister(instr->result()).is(eax));
3740
3741 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003742 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3743 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003744 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003745 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003746 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003747}
3748
3749
3750void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3751 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003752 CallKnownFunction(instr->target(),
3753 instr->arity(),
3754 instr,
3755 CALL_AS_FUNCTION,
3756 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003757}
3758
3759
3760void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003761 ASSERT(ToRegister(instr->context()).is(esi));
3762 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003763 ASSERT(ToRegister(instr->result()).is(eax));
3764
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003765 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003766 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003767 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003768}
3769
3770
3771void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003772 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003773}
3774
3775
3776void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3777 Register object = ToRegister(instr->object());
3778 Register value = ToRegister(instr->value());
3779 int offset = instr->offset();
3780
3781 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00003782 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
3783 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3784 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003785 Register temp = ToRegister(instr->temp());
3786 Register temp_map = ToRegister(instr->temp_map());
verwaest@chromium.org37141392012-05-31 13:27:02 +00003787 __ mov(temp_map, instr->transition());
3788 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
3789 // Update the write barrier for the map field.
3790 __ RecordWriteField(object,
3791 HeapObject::kMapOffset,
3792 temp_map,
3793 temp,
3794 kSaveFPRegs,
3795 OMIT_REMEMBERED_SET,
3796 OMIT_SMI_CHECK);
3797 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003798 }
3799
3800 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003801 HType type = instr->hydrogen()->value()->type();
3802 SmiCheck check_needed =
3803 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003804 if (instr->is_in_object()) {
3805 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003806 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003807 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003808 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003809 __ RecordWriteField(object,
3810 offset,
3811 value,
3812 temp,
3813 kSaveFPRegs,
3814 EMIT_REMEMBERED_SET,
3815 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003816 }
3817 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003818 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003819 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3820 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003821 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003822 // Update the write barrier for the properties array.
3823 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003824 __ RecordWriteField(temp,
3825 offset,
3826 value,
3827 object,
3828 kSaveFPRegs,
3829 EMIT_REMEMBERED_SET,
3830 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003831 }
3832 }
3833}
3834
3835
3836void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003837 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003838 ASSERT(ToRegister(instr->object()).is(edx));
3839 ASSERT(ToRegister(instr->value()).is(eax));
3840
3841 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003842 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003843 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3844 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003845 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003846}
3847
3848
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003849void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
3850 HValue* value,
3851 LOperand* operand) {
3852 if (value->representation().IsTagged() && !value->type().IsSmi()) {
3853 if (operand->IsRegister()) {
3854 __ test(ToRegister(operand), Immediate(kSmiTagMask));
3855 } else {
3856 __ test(ToOperand(operand), Immediate(kSmiTagMask));
3857 }
3858 DeoptimizeIf(not_zero, environment);
3859 }
3860}
3861
3862
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003863void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003864 DeoptIfTaggedButNotSmi(instr->environment(),
3865 instr->hydrogen()->length(),
3866 instr->length());
3867 DeoptIfTaggedButNotSmi(instr->environment(),
3868 instr->hydrogen()->index(),
3869 instr->index());
danno@chromium.orgb6451162011-08-17 14:33:23 +00003870 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003871 int constant_index =
3872 ToInteger32(LConstantOperand::cast(instr->index()));
3873 if (instr->hydrogen()->length()->representation().IsTagged()) {
3874 __ cmp(ToOperand(instr->length()),
3875 Immediate(Smi::FromInt(constant_index)));
3876 } else {
3877 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
3878 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003879 DeoptimizeIf(below_equal, instr->environment());
3880 } else {
3881 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3882 DeoptimizeIf(above_equal, instr->environment());
3883 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003884}
3885
3886
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003887void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003888 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003889 LOperand* key = instr->key();
3890 if (!key->IsConstantOperand() &&
3891 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3892 elements_kind)) {
3893 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003894 }
3895 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003896 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003897 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003898 instr->hydrogen()->key()->representation(),
3899 elements_kind,
3900 0,
3901 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003902 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003903 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003904 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003905 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003906 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003907 } else {
3908 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003909 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003910 case EXTERNAL_PIXEL_ELEMENTS:
3911 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3912 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003913 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003914 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003915 case EXTERNAL_SHORT_ELEMENTS:
3916 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003917 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003918 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003919 case EXTERNAL_INT_ELEMENTS:
3920 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003921 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003922 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003923 case EXTERNAL_FLOAT_ELEMENTS:
3924 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003925 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003926 case FAST_ELEMENTS:
3927 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003928 case FAST_HOLEY_SMI_ELEMENTS:
3929 case FAST_HOLEY_ELEMENTS:
3930 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003931 case DICTIONARY_ELEMENTS:
3932 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003933 UNREACHABLE();
3934 break;
3935 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003936 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003937}
3938
3939
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003940void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
3941 XMMRegister value = ToDoubleRegister(instr->value());
3942
3943 if (instr->NeedsCanonicalization()) {
3944 Label have_value;
3945
3946 __ ucomisd(value, value);
3947 __ j(parity_odd, &have_value); // NaN.
3948
3949 ExternalReference canonical_nan_reference =
3950 ExternalReference::address_of_canonical_non_hole_nan();
3951 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
3952 __ bind(&have_value);
3953 }
3954
3955 Operand double_store_operand = BuildFastArrayOperand(
3956 instr->elements(),
3957 instr->key(),
3958 instr->hydrogen()->key()->representation(),
3959 FAST_DOUBLE_ELEMENTS,
3960 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3961 instr->additional_index());
3962 __ movdbl(double_store_operand, value);
3963}
3964
3965
3966void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003967 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003968 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003969 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3970
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003971 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003972 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003973 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003974 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003975 FAST_ELEMENTS,
3976 FixedArray::kHeaderSize - kHeapObjectTag,
3977 instr->additional_index());
3978 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003979
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003980 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003981 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003982 HType type = instr->hydrogen()->value()->type();
3983 SmiCheck check_needed =
3984 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003985 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00003986 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003987 __ RecordWrite(elements,
3988 key,
3989 value,
3990 kSaveFPRegs,
3991 EMIT_REMEMBERED_SET,
3992 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003993 }
3994}
3995
3996
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003997void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
3998 // By cases...external, fast-double, fast
3999 if (instr->is_external()) {
4000 DoStoreKeyedExternalArray(instr);
4001 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4002 DoStoreKeyedFixedDoubleArray(instr);
4003 } else {
4004 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004005 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004006}
4007
4008
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004009void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004010 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004011 ASSERT(ToRegister(instr->object()).is(edx));
4012 ASSERT(ToRegister(instr->key()).is(ecx));
4013 ASSERT(ToRegister(instr->value()).is(eax));
4014
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004015 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004016 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4017 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004018 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004019}
4020
4021
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004022void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4023 Register object_reg = ToRegister(instr->object());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004024 Register new_map_reg = ToRegister(instr->new_map_temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004025
4026 Handle<Map> from_map = instr->original_map();
4027 Handle<Map> to_map = instr->transitioned_map();
4028 ElementsKind from_kind = from_map->elements_kind();
4029 ElementsKind to_kind = to_map->elements_kind();
4030
4031 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004032 bool is_simple_map_transition =
4033 IsSimpleMapChangeTransition(from_kind, to_kind);
4034 Label::Distance branch_distance =
4035 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004036 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004037 __ j(not_equal, &not_applicable, branch_distance);
4038 if (is_simple_map_transition) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004039 Register object_reg = ToRegister(instr->object());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004040 Handle<Map> map = instr->hydrogen()->transitioned_map();
4041 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4042 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004043 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004044 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004045 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004046 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004047 kDontSaveFPRegs);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004048 } else if (IsFastSmiElementsKind(from_kind) &&
4049 IsFastDoubleElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004050 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004051 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004052 ASSERT(fixed_object_reg.is(edx));
4053 ASSERT(new_map_reg.is(ebx));
4054 __ mov(fixed_object_reg, object_reg);
4055 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4056 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004057 } else if (IsFastDoubleElementsKind(from_kind) &&
4058 IsFastObjectElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004059 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004060 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004061 ASSERT(fixed_object_reg.is(edx));
4062 ASSERT(new_map_reg.is(ebx));
4063 __ mov(fixed_object_reg, object_reg);
4064 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4065 RelocInfo::CODE_TARGET, instr);
4066 } else {
4067 UNREACHABLE();
4068 }
4069 __ bind(&not_applicable);
4070}
4071
4072
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004073void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4074 class DeferredStringCharCodeAt: public LDeferredCode {
4075 public:
4076 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4077 : LDeferredCode(codegen), instr_(instr) { }
4078 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004079 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004080 private:
4081 LStringCharCodeAt* instr_;
4082 };
4083
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004084 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004085 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004086
erikcorry0ad885c2011-11-21 13:51:57 +00004087 StringCharLoadGenerator::Generate(masm(),
4088 factory(),
4089 ToRegister(instr->string()),
4090 ToRegister(instr->index()),
4091 ToRegister(instr->result()),
4092 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004093 __ bind(deferred->exit());
4094}
4095
4096
4097void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4098 Register string = ToRegister(instr->string());
4099 Register result = ToRegister(instr->result());
4100
4101 // TODO(3095996): Get rid of this. For now, we need to make the
4102 // result register contain a valid pointer because it is already
4103 // contained in the register pointer map.
4104 __ Set(result, Immediate(0));
4105
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004106 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004107 __ push(string);
4108 // Push the index as a smi. This is safe because of the checks in
4109 // DoStringCharCodeAt above.
4110 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4111 if (instr->index()->IsConstantOperand()) {
4112 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4113 __ push(Immediate(Smi::FromInt(const_index)));
4114 } else {
4115 Register index = ToRegister(instr->index());
4116 __ SmiTag(index);
4117 __ push(index);
4118 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004119 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4120 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004121 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004122 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004123 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004124}
4125
4126
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004127void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4128 class DeferredStringCharFromCode: public LDeferredCode {
4129 public:
4130 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4131 : LDeferredCode(codegen), instr_(instr) { }
4132 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004133 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004134 private:
4135 LStringCharFromCode* instr_;
4136 };
4137
4138 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004139 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004140
4141 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4142 Register char_code = ToRegister(instr->char_code());
4143 Register result = ToRegister(instr->result());
4144 ASSERT(!char_code.is(result));
4145
4146 __ cmp(char_code, String::kMaxAsciiCharCode);
4147 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004149 __ mov(result, FieldOperand(result,
4150 char_code, times_pointer_size,
4151 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004152 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004153 __ j(equal, deferred->entry());
4154 __ bind(deferred->exit());
4155}
4156
4157
4158void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4159 Register char_code = ToRegister(instr->char_code());
4160 Register result = ToRegister(instr->result());
4161
4162 // TODO(3095996): Get rid of this. For now, we need to make the
4163 // result register contain a valid pointer because it is already
4164 // contained in the register pointer map.
4165 __ Set(result, Immediate(0));
4166
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004167 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004168 __ SmiTag(char_code);
4169 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004170 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004171 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004172}
4173
4174
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004175void LCodeGen::DoStringLength(LStringLength* instr) {
4176 Register string = ToRegister(instr->string());
4177 Register result = ToRegister(instr->result());
4178 __ mov(result, FieldOperand(string, String::kLengthOffset));
4179}
4180
4181
danno@chromium.org160a7b02011-04-18 15:51:38 +00004182void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004183 EmitPushTaggedOperand(instr->left());
4184 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004185 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004186 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004187}
4188
4189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004190void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004191 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192 ASSERT(input->IsRegister() || input->IsStackSlot());
4193 LOperand* output = instr->result();
4194 ASSERT(output->IsDoubleRegister());
4195 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4196}
4197
4198
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004199void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004200 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004201 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004202 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004203
4204 __ LoadUint32(ToDoubleRegister(output),
4205 ToRegister(input),
4206 ToDoubleRegister(temp));
4207}
4208
4209
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004210void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4211 class DeferredNumberTagI: public LDeferredCode {
4212 public:
4213 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4214 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004215 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004216 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004217 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004218 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004219 private:
4220 LNumberTagI* instr_;
4221 };
4222
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004223 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004224 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4225 Register reg = ToRegister(input);
4226
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004227 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004228 __ SmiTag(reg);
4229 __ j(overflow, deferred->entry());
4230 __ bind(deferred->exit());
4231}
4232
4233
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004234void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4235 class DeferredNumberTagU: public LDeferredCode {
4236 public:
4237 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4238 : LDeferredCode(codegen), instr_(instr) { }
4239 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004240 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004241 }
4242 virtual LInstruction* instr() { return instr_; }
4243 private:
4244 LNumberTagU* instr_;
4245 };
4246
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004247 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004248 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4249 Register reg = ToRegister(input);
4250
4251 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4252 __ cmp(reg, Immediate(Smi::kMaxValue));
4253 __ j(above, deferred->entry());
4254 __ SmiTag(reg);
4255 __ bind(deferred->exit());
4256}
4257
4258
4259void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4260 LOperand* value,
4261 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004262 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004263 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004264 Register tmp = reg.is(eax) ? ecx : eax;
4265
4266 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004267 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004268
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004269 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004270
4271 if (signedness == SIGNED_INT32) {
4272 // There was overflow, so bits 30 and 31 of the original integer
4273 // disagree. Try to allocate a heap number in new space and store
4274 // the value in there. If that fails, call the runtime system.
4275 __ SmiUntag(reg);
4276 __ xor_(reg, 0x80000000);
4277 __ cvtsi2sd(xmm0, Operand(reg));
4278 } else {
4279 __ LoadUint32(xmm0, reg, xmm1);
4280 }
4281
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004282 if (FLAG_inline_new) {
4283 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004284 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004285 }
4286
4287 // Slow case: Call the runtime system to do the number allocation.
4288 __ bind(&slow);
4289
4290 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4291 // register is stored, as this register is in the pointer map, but contains an
4292 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004293 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004294 // NumberTagI and NumberTagD use the context from the frame, rather than
4295 // the environment's HContext or HInlinedContext value.
4296 // They only call Runtime::kAllocateHeapNumber.
4297 // The corresponding HChange instructions are added in a phase that does
4298 // not have easy access to the local context.
4299 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4300 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4301 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004302 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004303 if (!reg.is(eax)) __ mov(reg, eax);
4304
4305 // Done. Put the value in xmm0 into the value of the allocated heap
4306 // number.
4307 __ bind(&done);
4308 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004309 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004310}
4311
4312
4313void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4314 class DeferredNumberTagD: public LDeferredCode {
4315 public:
4316 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4317 : LDeferredCode(codegen), instr_(instr) { }
4318 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004319 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004320 private:
4321 LNumberTagD* instr_;
4322 };
4323
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004324 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004325 Register reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004326 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004327
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004328 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004329 if (FLAG_inline_new) {
4330 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4331 } else {
4332 __ jmp(deferred->entry());
4333 }
4334 __ bind(deferred->exit());
4335 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4336}
4337
4338
4339void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4340 // TODO(3095996): Get rid of this. For now, we need to make the
4341 // result register contain a valid pointer because it is already
4342 // contained in the register pointer map.
4343 Register reg = ToRegister(instr->result());
4344 __ Set(reg, Immediate(0));
4345
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004346 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004347 // NumberTagI and NumberTagD use the context from the frame, rather than
4348 // the environment's HContext or HInlinedContext value.
4349 // They only call Runtime::kAllocateHeapNumber.
4350 // The corresponding HChange instructions are added in a phase that does
4351 // not have easy access to the local context.
4352 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4353 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004354 RecordSafepointWithRegisters(
4355 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004356 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004357}
4358
4359
4360void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004361 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004362 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4363 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4364 __ SmiTag(ToRegister(input));
4365}
4366
4367
4368void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004369 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004370 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4371 if (instr->needs_check()) {
4372 __ test(ToRegister(input), Immediate(kSmiTagMask));
4373 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004374 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004375 __ AssertSmi(ToRegister(input));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004376 }
4377 __ SmiUntag(ToRegister(input));
4378}
4379
4380
4381void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004382 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004383 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004384 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004385 bool deoptimize_on_minus_zero,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004386 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004387 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004388
4389 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004390 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004391
4392 // Heap number map check.
4393 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004395 if (deoptimize_on_undefined) {
4396 DeoptimizeIf(not_equal, env);
4397 } else {
4398 Label heap_number;
4399 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004401 __ cmp(input_reg, factory()->undefined_value());
4402 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004404 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004405 ExternalReference nan =
4406 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004407 __ movdbl(result_reg, Operand::StaticVariable(nan));
4408 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004410 __ bind(&heap_number);
4411 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004412 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004413 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004414 if (deoptimize_on_minus_zero) {
4415 XMMRegister xmm_scratch = xmm0;
4416 __ xorps(xmm_scratch, xmm_scratch);
4417 __ ucomisd(result_reg, xmm_scratch);
4418 __ j(not_zero, &done, Label::kNear);
4419 __ movmskpd(temp_reg, result_reg);
4420 __ test_b(temp_reg, 1);
4421 DeoptimizeIf(not_zero, env);
4422 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004423 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004424
4425 // Smi to XMM conversion
4426 __ bind(&load_smi);
4427 __ SmiUntag(input_reg); // Untag smi before converting to float.
4428 __ cvtsi2sd(result_reg, Operand(input_reg));
4429 __ SmiTag(input_reg); // Retag smi.
4430 __ bind(&done);
4431}
4432
4433
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004434void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004435 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004436 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004437
4438 // Heap number map check.
4439 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004441
4442 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004443 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004444 // Check for undefined. Undefined is converted to zero for truncating
4445 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004447 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004448 DeoptimizeIf(not_equal, instr->environment());
4449 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004450 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004451
4452 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004453 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004454 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004455 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004456 // Use more powerful conversion when sse3 is available.
4457 // Load x87 register with heap number.
4458 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4459 // Get exponent alone and check for too-big exponent.
4460 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
4461 __ and_(input_reg, HeapNumber::kExponentMask);
4462 const uint32_t kTooBigExponent =
4463 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4464 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004465 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004466 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004467 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004468 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004469 DeoptimizeIf(no_condition, instr->environment());
4470
4471 // Reserve space for 64 bit answer.
4472 __ bind(&convert);
4473 __ sub(Operand(esp), Immediate(kDoubleSize));
4474 // Do conversion, which cannot fail because we checked the exponent.
4475 __ fisttp_d(Operand(esp, 0));
4476 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
4477 __ add(Operand(esp), Immediate(kDoubleSize));
4478 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004479 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004480 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4481 __ cvttsd2si(input_reg, Operand(xmm0));
4482 __ cmp(input_reg, 0x80000000u);
4483 __ j(not_equal, &done);
4484 // Check if the input was 0x8000000 (kMinInt).
4485 // If no, then we got an overflow and we deoptimize.
4486 ExternalReference min_int = ExternalReference::address_of_min_int();
4487 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
4488 __ ucomisd(xmm_temp, xmm0);
4489 DeoptimizeIf(not_equal, instr->environment());
4490 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4491 }
4492 } else {
4493 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004494 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004495 DeoptimizeIf(not_equal, instr->environment());
4496
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004497 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004498 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4499 __ cvttsd2si(input_reg, Operand(xmm0));
4500 __ cvtsi2sd(xmm_temp, Operand(input_reg));
4501 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004502 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004503 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004504 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004505 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4506 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4507 __ test(input_reg, Operand(input_reg));
4508 __ j(not_zero, &done);
4509 __ movmskpd(input_reg, xmm0);
4510 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004511 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004512 DeoptimizeIf(not_zero, instr->environment());
4513 }
4514 }
4515 __ bind(&done);
4516}
4517
4518
4519void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004520 class DeferredTaggedToI: public LDeferredCode {
4521 public:
4522 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4523 : LDeferredCode(codegen), instr_(instr) { }
4524 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4525 virtual LInstruction* instr() { return instr_; }
4526 private:
4527 LTaggedToI* instr_;
4528 };
4529
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004530 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004531 ASSERT(input->IsRegister());
4532 ASSERT(input->Equals(instr->result()));
4533
4534 Register input_reg = ToRegister(input);
4535
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004536 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004537
4538 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004539 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004540
4541 // Smi to int32 conversion
4542 __ SmiUntag(input_reg); // Untag smi.
4543
4544 __ bind(deferred->exit());
4545}
4546
4547
4548void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004549 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004550 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004551 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004552 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004553 LOperand* result = instr->result();
4554 ASSERT(result->IsDoubleRegister());
4555
4556 Register input_reg = ToRegister(input);
4557 XMMRegister result_reg = ToDoubleRegister(result);
4558
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004559 bool deoptimize_on_minus_zero =
4560 instr->hydrogen()->deoptimize_on_minus_zero();
4561 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
4562
4563 EmitNumberUntagD(input_reg,
4564 temp_reg,
4565 result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004566 instr->hydrogen()->deoptimize_on_undefined(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004567 deoptimize_on_minus_zero,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004568 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004569}
4570
4571
4572void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004573 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004574 ASSERT(input->IsDoubleRegister());
4575 LOperand* result = instr->result();
4576 ASSERT(result->IsRegister());
4577
4578 XMMRegister input_reg = ToDoubleRegister(input);
4579 Register result_reg = ToRegister(result);
4580
4581 if (instr->truncating()) {
4582 // Performs a truncating conversion of a floating point number as used by
4583 // the JS bitwise operations.
4584 __ cvttsd2si(result_reg, Operand(input_reg));
4585 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004586 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004587 // This will deoptimize if the exponent of the input in out of range.
4588 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004589 Label convert, done;
4590 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004591 __ sub(Operand(esp), Immediate(kDoubleSize));
4592 __ movdbl(Operand(esp, 0), input_reg);
4593 // Get exponent alone and check for too-big exponent.
4594 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
4595 __ and_(result_reg, HeapNumber::kExponentMask);
4596 const uint32_t kTooBigExponent =
4597 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4598 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004599 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004600 __ add(Operand(esp), Immediate(kDoubleSize));
4601 DeoptimizeIf(no_condition, instr->environment());
4602 __ bind(&convert);
4603 // Do conversion, which cannot fail because we checked the exponent.
4604 __ fld_d(Operand(esp, 0));
4605 __ fisttp_d(Operand(esp, 0));
4606 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
4607 __ add(Operand(esp), Immediate(kDoubleSize));
4608 __ bind(&done);
4609 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004610 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004611 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004612 XMMRegister xmm_scratch = xmm0;
4613
4614 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
4615 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004616 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004617
4618 // Get high 32 bits of the input in result_reg and temp_reg.
4619 __ pshufd(xmm_scratch, input_reg, 1);
4620 __ movd(Operand(temp_reg), xmm_scratch);
4621 __ mov(result_reg, temp_reg);
4622
4623 // Prepare negation mask in temp_reg.
4624 __ sar(temp_reg, kBitsPerInt - 1);
4625
4626 // Extract the exponent from result_reg and subtract adjusted
4627 // bias from it. The adjustment is selected in a way such that
4628 // when the difference is zero, the answer is in the low 32 bits
4629 // of the input, otherwise a shift has to be performed.
4630 __ shr(result_reg, HeapNumber::kExponentShift);
4631 __ and_(result_reg,
4632 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
4633 __ sub(Operand(result_reg),
4634 Immediate(HeapNumber::kExponentBias +
4635 HeapNumber::kExponentBits +
4636 HeapNumber::kMantissaBits));
4637 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
4638 // special exponents.
4639 DeoptimizeIf(greater, instr->environment());
4640
4641 // Zero out the sign and the exponent in the input (by shifting
4642 // it to the left) and restore the implicit mantissa bit,
4643 // i.e. convert the input to unsigned int64 shifted left by
4644 // kExponentBits.
4645 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
4646 // Minus zero has the most significant bit set and the other
4647 // bits cleared.
4648 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
4649 __ psllq(input_reg, HeapNumber::kExponentBits);
4650 __ por(input_reg, xmm_scratch);
4651
4652 // Get the amount to shift the input right in xmm_scratch.
4653 __ neg(result_reg);
4654 __ movd(xmm_scratch, Operand(result_reg));
4655
4656 // Shift the input right and extract low 32 bits.
4657 __ psrlq(input_reg, xmm_scratch);
4658 __ movd(Operand(result_reg), input_reg);
4659
4660 // Use the prepared mask in temp_reg to negate the result if necessary.
4661 __ xor_(result_reg, Operand(temp_reg));
4662 __ sub(result_reg, Operand(temp_reg));
4663 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004664 }
4665 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004666 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004667 __ cvttsd2si(result_reg, Operand(input_reg));
4668 __ cvtsi2sd(xmm0, Operand(result_reg));
4669 __ ucomisd(xmm0, input_reg);
4670 DeoptimizeIf(not_equal, instr->environment());
4671 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4672 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4673 // The integer converted back is equal to the original. We
4674 // only have to test if we got -0 as an input.
4675 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004676 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004677 __ movmskpd(result_reg, input_reg);
4678 // Bit 0 contains the sign of the double in input_reg.
4679 // If input was positive, we are ok and return 0, otherwise
4680 // deoptimize.
4681 __ and_(result_reg, 1);
4682 DeoptimizeIf(not_zero, instr->environment());
4683 }
4684 __ bind(&done);
4685 }
4686}
4687
4688
4689void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004690 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004691 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004692 DeoptimizeIf(not_zero, instr->environment());
4693}
4694
4695
4696void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004697 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004698 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004699 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004700}
4701
4702
4703void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004704 Register input = ToRegister(instr->value());
4705 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004706
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004707 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004708
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004709 if (instr->hydrogen()->is_interval_check()) {
4710 InstanceType first;
4711 InstanceType last;
4712 instr->hydrogen()->GetCheckInterval(&first, &last);
4713
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004714 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4715 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004716
4717 // If there is only one type in the interval check for equality.
4718 if (first == last) {
4719 DeoptimizeIf(not_equal, instr->environment());
4720 } else {
4721 DeoptimizeIf(below, instr->environment());
4722 // Omit check for the last type.
4723 if (last != LAST_TYPE) {
4724 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
4725 static_cast<int8_t>(last));
4726 DeoptimizeIf(above, instr->environment());
4727 }
4728 }
4729 } else {
4730 uint8_t mask;
4731 uint8_t tag;
4732 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4733
4734 if (IsPowerOf2(mask)) {
4735 ASSERT(tag == 0 || IsPowerOf2(tag));
4736 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
4737 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4738 } else {
4739 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4740 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00004741 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004742 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004743 }
4744 }
4745}
4746
4747
4748void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004749 Handle<JSFunction> target = instr->hydrogen()->target();
4750 if (isolate()->heap()->InNewSpace(*target)) {
4751 Register reg = ToRegister(instr->value());
4752 Handle<JSGlobalPropertyCell> cell =
4753 isolate()->factory()->NewJSGlobalPropertyCell(target);
4754 __ cmp(reg, Operand::Cell(cell));
4755 } else {
4756 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004757 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004758 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004759 DeoptimizeIf(not_equal, instr->environment());
4760}
4761
4762
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004763void LCodeGen::DoCheckMapCommon(Register reg,
4764 Handle<Map> map,
4765 CompareMapMode mode,
4766 LEnvironment* env) {
4767 Label success;
4768 __ CompareMap(reg, map, &success, mode);
4769 DeoptimizeIf(not_equal, env);
4770 __ bind(&success);
4771}
4772
4773
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004774void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004775 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776 ASSERT(input->IsRegister());
4777 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004778
4779 Label success;
4780 SmallMapList* map_set = instr->hydrogen()->map_set();
4781 for (int i = 0; i < map_set->length() - 1; i++) {
4782 Handle<Map> map = map_set->at(i);
4783 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
4784 __ j(equal, &success);
4785 }
4786 Handle<Map> map = map_set->last();
4787 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
4788 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004789}
4790
4791
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004792void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4793 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4794 Register result_reg = ToRegister(instr->result());
4795 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4796}
4797
4798
4799void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4800 ASSERT(instr->unclamped()->Equals(instr->result()));
4801 Register value_reg = ToRegister(instr->result());
4802 __ ClampUint8(value_reg);
4803}
4804
4805
4806void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4807 ASSERT(instr->unclamped()->Equals(instr->result()));
4808 Register input_reg = ToRegister(instr->unclamped());
4809 Label is_smi, done, heap_number;
4810
4811 __ JumpIfSmi(input_reg, &is_smi);
4812
4813 // Check for heap number
4814 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4815 factory()->heap_number_map());
4816 __ j(equal, &heap_number, Label::kNear);
4817
4818 // Check for undefined. Undefined is converted to zero for clamping
4819 // conversions.
4820 __ cmp(input_reg, factory()->undefined_value());
4821 DeoptimizeIf(not_equal, instr->environment());
4822 __ mov(input_reg, 0);
4823 __ jmp(&done, Label::kNear);
4824
4825 // Heap number
4826 __ bind(&heap_number);
4827 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4828 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4829 __ jmp(&done, Label::kNear);
4830
4831 // smi
4832 __ bind(&is_smi);
4833 __ SmiUntag(input_reg);
4834 __ ClampUint8(input_reg);
4835
4836 __ bind(&done);
4837}
4838
4839
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004840void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004841 ASSERT(instr->temp()->Equals(instr->result()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004842 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004843
4844 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004845 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004846
4847 // Load prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004848 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004849
4850 // Check prototype maps up to the holder.
4851 while (!current_prototype.is_identical_to(holder)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004852 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4853 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
4854
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004855 current_prototype =
4856 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4857 // Load next prototype object.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004858 __ LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004859 }
4860
4861 // Check the holder map.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004862 DoCheckMapCommon(reg, Handle<Map>(current_prototype->map()),
4863 ALLOW_ELEMENT_TRANSITION_MAPS, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004864}
4865
4866
ulan@chromium.org967e2702012-02-28 09:49:15 +00004867void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
4868 class DeferredAllocateObject: public LDeferredCode {
4869 public:
4870 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
4871 : LDeferredCode(codegen), instr_(instr) { }
4872 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
4873 virtual LInstruction* instr() { return instr_; }
4874 private:
4875 LAllocateObject* instr_;
4876 };
4877
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004878 DeferredAllocateObject* deferred =
4879 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00004880
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004881 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004882 Register scratch = ToRegister(instr->temp());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004883 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
4884 Handle<Map> initial_map(constructor->initial_map());
4885 int instance_size = initial_map->instance_size();
4886 ASSERT(initial_map->pre_allocated_property_fields() +
4887 initial_map->unused_property_fields() -
4888 initial_map->inobject_properties() == 0);
4889
4890 // Allocate memory for the object. The initial map might change when
4891 // the constructor's prototype changes, but instance size and property
4892 // counts remain unchanged (if slack tracking finished).
4893 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
4894 __ AllocateInNewSpace(instance_size,
4895 result,
4896 no_reg,
4897 scratch,
4898 deferred->entry(),
4899 TAG_OBJECT);
4900
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004901 __ bind(deferred->exit());
4902 if (FLAG_debug_code) {
4903 Label is_in_new_space;
4904 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
4905 __ Abort("Allocated object is not in new-space");
4906 __ bind(&is_in_new_space);
4907 }
4908
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004909 // Load the initial map.
4910 Register map = scratch;
4911 __ LoadHeapObject(scratch, constructor);
4912 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
4913
4914 if (FLAG_debug_code) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004915 __ AssertNotSmi(map);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00004916 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
4917 instance_size >> kPointerSizeLog2);
4918 __ Assert(equal, "Unexpected instance size");
4919 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
4920 initial_map->pre_allocated_property_fields());
4921 __ Assert(equal, "Unexpected pre-allocated property fields count");
4922 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
4923 initial_map->unused_property_fields());
4924 __ Assert(equal, "Unexpected unused property fields count");
4925 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
4926 initial_map->inobject_properties());
4927 __ Assert(equal, "Unexpected in-object property fields count");
4928 }
4929
4930 // Initialize map and fields of the newly allocated object.
4931 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
4932 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
4933 __ mov(scratch, factory()->empty_fixed_array());
4934 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
4935 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
4936 if (initial_map->inobject_properties() != 0) {
4937 __ mov(scratch, factory()->undefined_value());
4938 for (int i = 0; i < initial_map->inobject_properties(); i++) {
4939 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
4940 __ mov(FieldOperand(result, property_offset), scratch);
4941 }
4942 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00004943}
4944
4945
4946void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
4947 Register result = ToRegister(instr->result());
4948 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004949 Handle<Map> initial_map(constructor->initial_map());
4950 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00004951
4952 // TODO(3095996): Get rid of this. For now, we need to make the
4953 // result register contain a valid pointer because it is already
4954 // contained in the register pointer map.
4955 __ Set(result, Immediate(0));
4956
4957 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004958 __ push(Immediate(Smi::FromInt(instance_size)));
4959 CallRuntimeFromDeferred(
4960 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00004961 __ StoreToSafepointRegisterSlot(result, eax);
4962}
4963
4964
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004966 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004967 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004968 ElementsKind boilerplate_elements_kind =
4969 instr->hydrogen()->boilerplate_elements_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004970
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004971 // Deopt if the array literal boilerplate ElementsKind is of a type different
4972 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004973 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
4974 if (CanTransitionToMoreGeneralFastElementsKind(
4975 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004976 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
4977 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
4978 // Load the map's "bit field 2". We only need the first byte,
4979 // but the following masking takes care of that anyway.
4980 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
4981 // Retrieve elements_kind from bit field 2.
4982 __ and_(ebx, Map::kElementsKindMask);
4983 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
4984 DeoptimizeIf(not_equal, instr->environment());
4985 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004986
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004987 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004988 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004989 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004990 // Boilerplate already exists, constant elements are never accessed.
4991 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00004992 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004993
4994 // Pick the right runtime function or stub to call.
4995 int length = instr->hydrogen()->length();
4996 if (instr->hydrogen()->IsCopyOnWrite()) {
4997 ASSERT(instr->hydrogen()->depth() == 1);
4998 FastCloneShallowArrayStub::Mode mode =
4999 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
5000 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005001 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005002 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005003 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005004 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005005 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005006 } else {
5007 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005008 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
5009 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
5010 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005011 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005012 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005013 }
5014}
5015
5016
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005017void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
5018 Register result,
5019 Register source,
5020 int* offset) {
5021 ASSERT(!source.is(ecx));
5022 ASSERT(!result.is(ecx));
5023
5024 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005025 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005026 __ cmp(source, ecx);
5027 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005028 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
5029 __ cmp(ecx, Handle<Map>(object->map()));
5030 __ Assert(equal, "Unexpected boilerplate map");
5031 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5032 __ and_(ecx, Map::kElementsKindMask);
5033 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
5034 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005035 }
5036
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005037 // Only elements backing stores for non-COW arrays need to be copied.
5038 Handle<FixedArrayBase> elements(object->elements());
5039 bool has_elements = elements->length() > 0 &&
5040 elements->map() != isolate()->heap()->fixed_cow_array_map();
5041
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005042 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005043 // this object and its backing store.
5044 int object_offset = *offset;
5045 int object_size = object->map()->instance_size();
5046 int elements_offset = *offset + object_size;
5047 int elements_size = has_elements ? elements->Size() : 0;
5048 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005049
5050 // Copy object header.
5051 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005052 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005053 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005054 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005055 if (has_elements && i == JSObject::kElementsOffset) {
5056 __ lea(ecx, Operand(result, elements_offset));
5057 } else {
5058 __ mov(ecx, FieldOperand(source, i));
5059 }
5060 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005061 }
5062
5063 // Copy in-object properties.
5064 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005065 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005066 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
5067 if (value->IsJSObject()) {
5068 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5069 __ lea(ecx, Operand(result, *offset));
5070 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005071 __ LoadHeapObject(source, value_object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005072 EmitDeepCopy(value_object, result, source, offset);
5073 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005074 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005075 __ mov(FieldOperand(result, total_offset), ecx);
5076 } else {
5077 __ mov(FieldOperand(result, total_offset), Immediate(value));
5078 }
5079 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005080
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005081 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005082 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005083 __ LoadHeapObject(source, elements);
5084 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
5085 __ mov(ecx, FieldOperand(source, i));
5086 __ mov(FieldOperand(result, elements_offset + i), ecx);
5087 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005088
danno@chromium.org88aa0582012-03-23 15:11:57 +00005089 // Copy elements backing store content.
5090 int elements_length = elements->length();
5091 if (elements->IsFixedDoubleArray()) {
5092 Handle<FixedDoubleArray> double_array =
5093 Handle<FixedDoubleArray>::cast(elements);
5094 for (int i = 0; i < elements_length; i++) {
5095 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005096 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
5097 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005098 int total_offset =
5099 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
5100 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
5101 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
5102 }
5103 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005104 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005105 for (int i = 0; i < elements_length; i++) {
5106 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005107 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00005108 if (value->IsJSObject()) {
5109 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5110 __ lea(ecx, Operand(result, *offset));
5111 __ mov(FieldOperand(result, total_offset), ecx);
5112 __ LoadHeapObject(source, value_object);
5113 EmitDeepCopy(value_object, result, source, offset);
5114 } else if (value->IsHeapObject()) {
5115 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5116 __ mov(FieldOperand(result, total_offset), ecx);
5117 } else {
5118 __ mov(FieldOperand(result, total_offset), Immediate(value));
5119 }
5120 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005121 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005122 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005123 }
5124 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005125}
5126
5127
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005128void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005129 ASSERT(ToRegister(instr->context()).is(esi));
5130 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005131 ElementsKind boilerplate_elements_kind =
5132 instr->hydrogen()->boilerplate()->GetElementsKind();
5133
5134 // Deopt if the literal boilerplate ElementsKind is of a type different than
5135 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005136 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5137 if (CanTransitionToMoreGeneralFastElementsKind(
5138 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005139 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5140 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5141 // Load the map's "bit field 2". We only need the first byte,
5142 // but the following masking takes care of that anyway.
5143 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5144 // Retrieve elements_kind from bit field 2.
5145 __ and_(ecx, Map::kElementsKindMask);
5146 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5147 DeoptimizeIf(not_equal, instr->environment());
5148 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005149
5150 // Allocate all objects that are part of the literal in one big
5151 // allocation. This avoids multiple limit checks.
5152 Label allocated, runtime_allocate;
5153 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5154 __ jmp(&allocated);
5155
5156 __ bind(&runtime_allocate);
5157 __ push(Immediate(Smi::FromInt(size)));
5158 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5159
5160 __ bind(&allocated);
5161 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005162 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005163 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset);
5164 ASSERT_EQ(size, offset);
5165}
5166
5167
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005168void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005169 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005170 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005171 Handle<FixedArray> constant_properties =
5172 instr->hydrogen()->constant_properties();
5173
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005174 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005175 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005176 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005177 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005178 int flags = instr->hydrogen()->fast_elements()
5179 ? ObjectLiteral::kFastElements
5180 : ObjectLiteral::kNoFlags;
5181 flags |= instr->hydrogen()->has_function()
5182 ? ObjectLiteral::kHasFunction
5183 : ObjectLiteral::kNoFlags;
5184 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005185
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005186 // Pick the right runtime function or stub to call.
5187 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005188 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005189 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005190 } else if (flags != ObjectLiteral::kFastElements ||
5191 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005192 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005193 } else {
5194 FastCloneShallowObjectStub stub(properties_count);
5195 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005196 }
5197}
5198
5199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005201 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005202 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005203 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204}
5205
5206
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005207void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005208 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005209 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005210 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005211 // ecx = literals array.
5212 // ebx = regexp literal.
5213 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005214 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005215 int literal_offset =
5216 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5217 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005218 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005220 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005221
5222 // Create regexp literal using runtime function
5223 // Result will be in eax.
5224 __ push(ecx);
5225 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5226 __ push(Immediate(instr->hydrogen()->pattern()));
5227 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005228 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005229 __ mov(ebx, eax);
5230
5231 __ bind(&materialized);
5232 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5233 Label allocated, runtime_allocate;
5234 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5235 __ jmp(&allocated);
5236
5237 __ bind(&runtime_allocate);
5238 __ push(ebx);
5239 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005240 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241 __ pop(ebx);
5242
5243 __ bind(&allocated);
5244 // Copy the content into the newly allocated memory.
5245 // (Unroll copy loop once for better throughput).
5246 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5247 __ mov(edx, FieldOperand(ebx, i));
5248 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5249 __ mov(FieldOperand(eax, i), edx);
5250 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5251 }
5252 if ((size % (2 * kPointerSize)) != 0) {
5253 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5254 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5255 }
5256}
5257
5258
5259void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005260 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005261 // Use the fast case closure allocation code that allocates in new
5262 // space for nested functions that don't need literals cloning.
5263 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005264 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005266 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005267 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005268 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005269 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005270 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005271 __ push(Immediate(shared_info));
5272 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005273 ? factory()->true_value()
5274 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005275 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005276 }
5277}
5278
5279
5280void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005281 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005282 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005283 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005284}
5285
5286
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005287void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005288 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005289 int true_block = chunk_->LookupDestination(instr->true_block_id());
5290 int false_block = chunk_->LookupDestination(instr->false_block_id());
5291 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5292 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5293
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005294 Condition final_branch_condition =
5295 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5296 if (final_branch_condition != no_condition) {
5297 EmitBranch(true_block, false_block, final_branch_condition);
5298 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005299}
5300
5301
5302Condition LCodeGen::EmitTypeofIs(Label* true_label,
5303 Label* false_label,
5304 Register input,
5305 Handle<String> type_name) {
5306 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005307 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005308 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005309 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005311 final_branch_condition = equal;
5312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005313 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005314 __ JumpIfSmi(input, false_label);
5315 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5316 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005317 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5318 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005319 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005321 } else if (type_name->Equals(heap()->boolean_symbol())) {
5322 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005323 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005324 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005325 final_branch_condition = equal;
5326
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005327 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
5328 __ cmp(input, factory()->null_value());
5329 final_branch_condition = equal;
5330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005331 } else if (type_name->Equals(heap()->undefined_symbol())) {
5332 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005333 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005334 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005335 // Check for undetectable objects => true.
5336 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5337 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5338 1 << Map::kIsUndetectable);
5339 final_branch_condition = not_zero;
5340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005342 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005343 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005344 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5345 __ j(equal, true_label);
5346 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5347 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005349 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005350 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005351 if (!FLAG_harmony_typeof) {
5352 __ cmp(input, factory()->null_value());
5353 __ j(equal, true_label);
5354 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005355 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005356 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005357 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5358 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005359 // Check for undetectable objects => false.
5360 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5361 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005362 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005363
5364 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005365 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005366 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005367 return final_branch_condition;
5368}
5369
5370
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005371void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005372 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005373 int true_block = chunk_->LookupDestination(instr->true_block_id());
5374 int false_block = chunk_->LookupDestination(instr->false_block_id());
5375
5376 EmitIsConstructCall(temp);
5377 EmitBranch(true_block, false_block, equal);
5378}
5379
5380
5381void LCodeGen::EmitIsConstructCall(Register temp) {
5382 // Get the frame pointer for the calling frame.
5383 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5384
5385 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005386 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005387 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5388 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005389 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005390 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5391
5392 // Check the marker in the calling frame.
5393 __ bind(&check_frame_marker);
5394 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5395 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5396}
5397
5398
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005399void LCodeGen::EnsureSpaceForLazyDeopt() {
5400 // Ensure that we have enough space after the previous lazy-bailout
5401 // instruction for patching the code here.
5402 int current_pc = masm()->pc_offset();
5403 int patch_size = Deoptimizer::patch_size();
5404 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5405 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005406 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005407 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005408 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005409}
5410
5411
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005412void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005413 EnsureSpaceForLazyDeopt();
5414 ASSERT(instr->HasEnvironment());
5415 LEnvironment* env = instr->environment();
5416 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5417 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005418}
5419
5420
5421void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5422 DeoptimizeIf(no_condition, instr->environment());
5423}
5424
5425
5426void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5427 LOperand* obj = instr->object();
5428 LOperand* key = instr->key();
5429 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005430 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005431 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005432 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005433 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005434 // Create safepoint generator that will also ensure enough space in the
5435 // reloc info for patching in deoptimization (since this is invoking a
5436 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005437 SafepointGenerator safepoint_generator(
5438 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005439 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005440 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005441}
5442
5443
ager@chromium.org04921a82011-06-27 13:21:41 +00005444void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005445 PushSafepointRegistersScope scope(this);
5446 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5447 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5448 RecordSafepointWithLazyDeopt(
5449 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5450 ASSERT(instr->HasEnvironment());
5451 LEnvironment* env = instr->environment();
5452 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005453}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005454
ager@chromium.org04921a82011-06-27 13:21:41 +00005455
5456void LCodeGen::DoStackCheck(LStackCheck* instr) {
5457 class DeferredStackCheck: public LDeferredCode {
5458 public:
5459 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5460 : LDeferredCode(codegen), instr_(instr) { }
5461 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005462 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005463 private:
5464 LStackCheck* instr_;
5465 };
5466
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005467 ASSERT(instr->HasEnvironment());
5468 LEnvironment* env = instr->environment();
5469 // There is no LLazyBailout instruction for stack-checks. We have to
5470 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005471 if (instr->hydrogen()->is_function_entry()) {
5472 // Perform stack overflow check.
5473 Label done;
5474 ExternalReference stack_limit =
5475 ExternalReference::address_of_stack_limit(isolate());
5476 __ cmp(esp, Operand::StaticVariable(stack_limit));
5477 __ j(above_equal, &done, Label::kNear);
5478
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005479 ASSERT(instr->context()->IsRegister());
5480 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00005481 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005482 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005483 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005484 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005485 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5486 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005487 } else {
5488 ASSERT(instr->hydrogen()->is_backwards_branch());
5489 // Perform stack overflow check if this goto needs it before jumping.
5490 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005491 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005492 ExternalReference stack_limit =
5493 ExternalReference::address_of_stack_limit(isolate());
5494 __ cmp(esp, Operand::StaticVariable(stack_limit));
5495 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005496 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005497 __ bind(instr->done_label());
5498 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005499 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5500 // Don't record a deoptimization index for the safepoint here.
5501 // This will be done explicitly when emitting call and the safepoint in
5502 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005503 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005504}
5505
5506
5507void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5508 // This is a pseudo-instruction that ensures that the environment here is
5509 // properly registered for deoptimization and records the assembler's PC
5510 // offset.
5511 LEnvironment* environment = instr->environment();
5512 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
5513 instr->SpilledDoubleRegisterArray());
5514
5515 // If the environment were already registered, we would have no way of
5516 // backpatching it with the spill slot operands.
5517 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005518 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005519 ASSERT(osr_pc_offset_ == -1);
5520 osr_pc_offset_ = masm()->pc_offset();
5521}
5522
5523
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005524void LCodeGen::DoIn(LIn* instr) {
5525 LOperand* obj = instr->object();
5526 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005527 EmitPushTaggedOperand(key);
5528 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005529 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005530 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005531 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005532 SafepointGenerator safepoint_generator(
5533 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005534 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005535}
5536
5537
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005538void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5539 __ cmp(eax, isolate()->factory()->undefined_value());
5540 DeoptimizeIf(equal, instr->environment());
5541
5542 __ cmp(eax, isolate()->factory()->null_value());
5543 DeoptimizeIf(equal, instr->environment());
5544
5545 __ test(eax, Immediate(kSmiTagMask));
5546 DeoptimizeIf(zero, instr->environment());
5547
5548 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5549 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5550 DeoptimizeIf(below_equal, instr->environment());
5551
5552 Label use_cache, call_runtime;
5553 __ CheckEnumCache(&call_runtime);
5554
5555 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5556 __ jmp(&use_cache, Label::kNear);
5557
5558 // Get the set of properties to enumerate.
5559 __ bind(&call_runtime);
5560 __ push(eax);
5561 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5562
5563 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5564 isolate()->factory()->meta_map());
5565 DeoptimizeIf(not_equal, instr->environment());
5566 __ bind(&use_cache);
5567}
5568
5569
5570void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5571 Register map = ToRegister(instr->map());
5572 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005573 Label load_cache, done;
5574 __ EnumLength(result, map);
5575 __ cmp(result, Immediate(Smi::FromInt(0)));
5576 __ j(not_equal, &load_cache);
5577 __ mov(result, isolate()->factory()->empty_fixed_array());
5578 __ jmp(&done);
5579
5580 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005581 __ LoadInstanceDescriptors(map, result);
5582 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005583 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005584 __ mov(result,
5585 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005586 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005587 __ test(result, result);
5588 DeoptimizeIf(equal, instr->environment());
5589}
5590
5591
5592void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5593 Register object = ToRegister(instr->value());
5594 __ cmp(ToRegister(instr->map()),
5595 FieldOperand(object, HeapObject::kMapOffset));
5596 DeoptimizeIf(not_equal, instr->environment());
5597}
5598
5599
5600void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5601 Register object = ToRegister(instr->object());
5602 Register index = ToRegister(instr->index());
5603
5604 Label out_of_object, done;
5605 __ cmp(index, Immediate(0));
5606 __ j(less, &out_of_object);
5607 __ mov(object, FieldOperand(object,
5608 index,
5609 times_half_pointer_size,
5610 JSObject::kHeaderSize));
5611 __ jmp(&done, Label::kNear);
5612
5613 __ bind(&out_of_object);
5614 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5615 __ neg(index);
5616 // Index is now equal to out of object property index plus 1.
5617 __ mov(object, FieldOperand(object,
5618 index,
5619 times_half_pointer_size,
5620 FixedArray::kHeaderSize - kPointerSize));
5621 __ bind(&done);
5622}
5623
5624
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005625#undef __
5626
5627} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005628
5629#endif // V8_TARGET_ARCH_IA32