blob: 841be732644ca0ae4b080aaddfbef65bd574be07 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
33#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000034#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "stub-cache.h"
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() {
70 HPhase phase("Code generation", chunk());
71 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
82 dynamic_frame_alignment_ = chunk()->num_double_slots() > 2 ||
83 info()->osr_ast_id() != AstNode::kNoNumber;
84
kasperl@chromium.orga5551262010-12-07 12:49:48 +000085 return GeneratePrologue() &&
86 GenerateBody() &&
87 GenerateDeferredCode() &&
88 GenerateSafepointTable();
89}
90
91
92void LCodeGen::FinishCode(Handle<Code> code) {
93 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000094 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000095 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000096 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000097 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000098}
99
100
101void LCodeGen::Abort(const char* format, ...) {
102 if (FLAG_trace_bailout) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000103 SmartArrayPointer<char> name(
104 info()->shared_info()->DebugName()->ToCString());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000105 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000106 va_list arguments;
107 va_start(arguments, format);
108 OS::VPrint(format, arguments);
109 va_end(arguments);
110 PrintF("\n");
111 }
112 status_ = ABORTED;
113}
114
115
116void LCodeGen::Comment(const char* format, ...) {
117 if (!FLAG_code_comments) return;
118 char buffer[4 * KB];
119 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
120 va_list arguments;
121 va_start(arguments, format);
122 builder.AddFormattedList(format, arguments);
123 va_end(arguments);
124
125 // Copy the string before recording it in the assembler to avoid
126 // issues when the stack allocated buffer goes out of scope.
127 size_t length = builder.position();
128 Vector<char> copy = Vector<char>::New(length + 1);
129 memcpy(copy.start(), builder.Finalize(), copy.length());
130 masm()->RecordComment(copy.start());
131}
132
133
134bool LCodeGen::GeneratePrologue() {
135 ASSERT(is_generating());
136
137#ifdef DEBUG
138 if (strlen(FLAG_stop_at) > 0 &&
139 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
140 __ int3();
141 }
142#endif
143
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000144 // Strict mode functions and builtins need to replace the receiver
145 // with undefined when called as functions (without an explicit
146 // receiver object). ecx is zero for method calls and non-zero for
147 // function calls.
148 if (info_->is_strict_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000149 Label ok;
150 __ test(ecx, Operand(ecx));
151 __ j(zero, &ok, Label::kNear);
152 // +1 for return address.
153 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
154 __ mov(Operand(esp, receiver_offset),
155 Immediate(isolate()->factory()->undefined_value()));
156 __ bind(&ok);
157 }
158
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000159 if (dynamic_frame_alignment_) {
160 Label do_not_pad, align_loop;
161 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
162 // Align esp to a multiple of 2 * kPointerSize.
163 __ test(esp, Immediate(kPointerSize));
164 __ j(zero, &do_not_pad, Label::kNear);
165 __ push(Immediate(0));
166 __ mov(ebx, esp);
167 // Copy arguments, receiver, and return address.
168 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
169
170 __ bind(&align_loop);
171 __ mov(eax, Operand(ebx, 1 * kPointerSize));
172 __ mov(Operand(ebx, 0), eax);
173 __ add(Operand(ebx), Immediate(kPointerSize));
174 __ dec(ecx);
175 __ j(not_zero, &align_loop, Label::kNear);
176 __ mov(Operand(ebx, 0),
177 Immediate(isolate()->factory()->frame_alignment_marker()));
178
179 __ bind(&do_not_pad);
180 }
181
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000182 __ push(ebp); // Caller's frame pointer.
183 __ mov(ebp, esp);
184 __ push(esi); // Callee's context.
185 __ push(edi); // Callee's JS function.
186
187 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000188 int slots = GetStackSlotCount();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000189 if (slots > 0) {
190 if (FLAG_debug_code) {
191 __ mov(Operand(eax), Immediate(slots));
192 Label loop;
193 __ bind(&loop);
194 __ push(Immediate(kSlotsZapValue));
195 __ dec(eax);
196 __ j(not_zero, &loop);
197 } else {
198 __ sub(Operand(esp), Immediate(slots * kPointerSize));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000199#ifdef _MSC_VER
200 // On windows, you may not access the stack more than one page below
201 // the most recently mapped page. To make the allocated area randomly
202 // accessible, we write to each page in turn (the value is irrelevant).
203 const int kPageSize = 4 * KB;
204 for (int offset = slots * kPointerSize - kPageSize;
205 offset > 0;
206 offset -= kPageSize) {
207 __ mov(Operand(esp, offset), eax);
208 }
209#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000210 }
211 }
212
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000213 // Possibly allocate a local context.
214 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
215 if (heap_slots > 0) {
216 Comment(";;; Allocate local context");
217 // Argument to NewContext is the function, which is still in edi.
218 __ push(edi);
219 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
220 FastNewContextStub stub(heap_slots);
221 __ CallStub(&stub);
222 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000223 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000224 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000225 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000226 // Context is returned in both eax and esi. It replaces the context
227 // passed to us. It's saved in the stack and kept live in esi.
228 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
229
230 // Copy parameters into context if necessary.
231 int num_parameters = scope()->num_parameters();
232 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000233 Variable* var = scope()->parameter(i);
234 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000235 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
236 (num_parameters - 1 - i) * kPointerSize;
237 // Load parameter from stack.
238 __ mov(eax, Operand(ebp, parameter_offset));
239 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000240 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000241 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000242 // Update the write barrier. This clobbers eax and ebx.
243 __ RecordWriteContextSlot(esi,
244 context_offset,
245 eax,
246 ebx,
247 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000248 }
249 }
250 Comment(";;; End allocate local context");
251 }
252
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000253 // Trace the call.
254 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000255 // We have not executed any compiled code yet, so esi still holds the
256 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000257 __ CallRuntime(Runtime::kTraceEnter, 0);
258 }
259 return !is_aborted();
260}
261
262
263bool LCodeGen::GenerateBody() {
264 ASSERT(is_generating());
265 bool emit_instructions = true;
266 for (current_instruction_ = 0;
267 !is_aborted() && current_instruction_ < instructions_->length();
268 current_instruction_++) {
269 LInstruction* instr = instructions_->at(current_instruction_);
270 if (instr->IsLabel()) {
271 LLabel* label = LLabel::cast(instr);
272 emit_instructions = !label->HasReplacement();
273 }
274
275 if (emit_instructions) {
276 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
277 instr->CompileToNative(this);
278 }
279 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000280 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000281 return !is_aborted();
282}
283
284
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000285bool LCodeGen::GenerateDeferredCode() {
286 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000287 if (deferred_.length() > 0) {
288 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
289 LDeferredCode* code = deferred_[i];
290 __ bind(code->entry());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000291 Comment(";;; Deferred code @%d: %s.",
292 code->instruction_index(),
293 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000294 code->Generate();
295 __ jmp(code->exit());
296 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000297 }
298
299 // Deferred code is the last part of the instruction sequence. Mark
300 // the generated code as done unless we bailed out.
301 if (!is_aborted()) status_ = DONE;
302 return !is_aborted();
303}
304
305
306bool LCodeGen::GenerateSafepointTable() {
307 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000308 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 return !is_aborted();
310}
311
312
313Register LCodeGen::ToRegister(int index) const {
314 return Register::FromAllocationIndex(index);
315}
316
317
318XMMRegister LCodeGen::ToDoubleRegister(int index) const {
319 return XMMRegister::FromAllocationIndex(index);
320}
321
322
323Register LCodeGen::ToRegister(LOperand* op) const {
324 ASSERT(op->IsRegister());
325 return ToRegister(op->index());
326}
327
328
329XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
330 ASSERT(op->IsDoubleRegister());
331 return ToDoubleRegister(op->index());
332}
333
334
335int LCodeGen::ToInteger32(LConstantOperand* op) const {
336 Handle<Object> value = chunk_->LookupLiteral(op);
337 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
338 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
339 value->Number());
340 return static_cast<int32_t>(value->Number());
341}
342
343
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000344double LCodeGen::ToDouble(LConstantOperand* op) const {
345 Handle<Object> value = chunk_->LookupLiteral(op);
346 return value->Number();
347}
348
349
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000350Immediate LCodeGen::ToImmediate(LOperand* op) {
351 LConstantOperand* const_op = LConstantOperand::cast(op);
352 Handle<Object> literal = chunk_->LookupLiteral(const_op);
353 Representation r = chunk_->LookupLiteralRepresentation(const_op);
354 if (r.IsInteger32()) {
355 ASSERT(literal->IsNumber());
356 return Immediate(static_cast<int32_t>(literal->Number()));
357 } else if (r.IsDouble()) {
358 Abort("unsupported double immediate");
359 }
360 ASSERT(r.IsTagged());
361 return Immediate(literal);
362}
363
364
365Operand LCodeGen::ToOperand(LOperand* op) const {
366 if (op->IsRegister()) return Operand(ToRegister(op));
367 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
368 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
369 int index = op->index();
370 if (index >= 0) {
371 // Local or spill slot. Skip the frame pointer, function, and
372 // context in the fixed part of the frame.
373 return Operand(ebp, -(index + 3) * kPointerSize);
374 } else {
375 // Incoming parameter. Skip the return address.
376 return Operand(ebp, -(index - 1) * kPointerSize);
377 }
378}
379
380
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000381Operand LCodeGen::HighOperand(LOperand* op) {
382 ASSERT(op->IsDoubleStackSlot());
383 int index = op->index();
384 int offset = (index >= 0) ? index + 3 : index - 1;
385 return Operand(ebp, -offset * kPointerSize);
386}
387
388
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000389void LCodeGen::WriteTranslation(LEnvironment* environment,
390 Translation* translation) {
391 if (environment == NULL) return;
392
393 // The translation includes one command per value in the environment.
394 int translation_size = environment->values()->length();
395 // The output frame height does not include the parameters.
396 int height = translation_size - environment->parameter_count();
397
398 WriteTranslation(environment->outer(), translation);
399 int closure_id = DefineDeoptimizationLiteral(environment->closure());
400 translation->BeginFrame(environment->ast_id(), closure_id, height);
401 for (int i = 0; i < translation_size; ++i) {
402 LOperand* value = environment->values()->at(i);
403 // spilled_registers_ and spilled_double_registers_ are either
404 // both NULL or both set.
405 if (environment->spilled_registers() != NULL && value != NULL) {
406 if (value->IsRegister() &&
407 environment->spilled_registers()[value->index()] != NULL) {
408 translation->MarkDuplicate();
409 AddToTranslation(translation,
410 environment->spilled_registers()[value->index()],
411 environment->HasTaggedValueAt(i));
412 } else if (
413 value->IsDoubleRegister() &&
414 environment->spilled_double_registers()[value->index()] != NULL) {
415 translation->MarkDuplicate();
416 AddToTranslation(
417 translation,
418 environment->spilled_double_registers()[value->index()],
419 false);
420 }
421 }
422
423 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
424 }
425}
426
427
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000428void LCodeGen::AddToTranslation(Translation* translation,
429 LOperand* op,
430 bool is_tagged) {
431 if (op == NULL) {
432 // TODO(twuerthinger): Introduce marker operands to indicate that this value
433 // is not present and must be reconstructed from the deoptimizer. Currently
434 // this is only used for the arguments object.
435 translation->StoreArgumentsObject();
436 } else if (op->IsStackSlot()) {
437 if (is_tagged) {
438 translation->StoreStackSlot(op->index());
439 } else {
440 translation->StoreInt32StackSlot(op->index());
441 }
442 } else if (op->IsDoubleStackSlot()) {
443 translation->StoreDoubleStackSlot(op->index());
444 } else if (op->IsArgument()) {
445 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000446 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 translation->StoreStackSlot(src_index);
448 } else if (op->IsRegister()) {
449 Register reg = ToRegister(op);
450 if (is_tagged) {
451 translation->StoreRegister(reg);
452 } else {
453 translation->StoreInt32Register(reg);
454 }
455 } else if (op->IsDoubleRegister()) {
456 XMMRegister reg = ToDoubleRegister(op);
457 translation->StoreDoubleRegister(reg);
458 } else if (op->IsConstantOperand()) {
459 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
460 int src_index = DefineDeoptimizationLiteral(literal);
461 translation->StoreLiteral(src_index);
462 } else {
463 UNREACHABLE();
464 }
465}
466
467
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000468void LCodeGen::CallCodeGeneric(Handle<Code> code,
469 RelocInfo::Mode mode,
470 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000471 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000472 ASSERT(instr != NULL);
473 LPointerMap* pointers = instr->pointer_map();
474 RecordPosition(pointers->position());
475 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000476 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000477
478 // Signal that we don't inline smi code before these stubs in the
479 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000480 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000481 code->kind() == Code::COMPARE_IC) {
482 __ nop();
483 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000484}
485
486
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000487void LCodeGen::CallCode(Handle<Code> code,
488 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000489 LInstruction* instr) {
490 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000491}
492
493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000494void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000495 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000496 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000497 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000498 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000499 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000500 RecordPosition(pointers->position());
501
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000502 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000503
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000504 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505}
506
507
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000508void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
509 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000510 LInstruction* instr,
511 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000512 if (context->IsRegister()) {
513 if (!ToRegister(context).is(esi)) {
514 __ mov(esi, ToRegister(context));
515 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000516 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000517 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 } else if (context->IsConstantOperand()) {
519 Handle<Object> literal =
520 chunk_->LookupLiteral(LConstantOperand::cast(context));
521 LoadHeapObject(esi, Handle<Context>::cast(literal));
522 } else {
523 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000524 }
525
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000526 __ CallRuntimeSaveDoubles(id);
527 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000528 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000529}
530
531
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000532void LCodeGen::RegisterEnvironmentForDeoptimization(
533 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534 if (!environment->HasBeenRegistered()) {
535 // Physical stack frame layout:
536 // -x ............. -4 0 ..................................... y
537 // [incoming arguments] [spill slots] [pushed outgoing arguments]
538
539 // Layout of the environment:
540 // 0 ..................................................... size-1
541 // [parameters] [locals] [expression stack including arguments]
542
543 // Layout of the translation:
544 // 0 ........................................................ size - 1 + 4
545 // [expression stack including arguments] [locals] [4 words] [parameters]
546 // |>------------ translation_size ------------<|
547
548 int frame_count = 0;
549 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
550 ++frame_count;
551 }
552 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000553 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000554 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000555 int pc_offset = masm()->pc_offset();
556 environment->Register(deoptimization_index,
557 translation.index(),
558 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000559 deoptimizations_.Add(environment);
560 }
561}
562
563
564void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000565 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000566 ASSERT(environment->HasBeenRegistered());
567 int id = environment->deoptimization_index();
568 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
569 ASSERT(entry != NULL);
570 if (entry == NULL) {
571 Abort("bailout was not prepared");
572 return;
573 }
574
575 if (FLAG_deopt_every_n_times != 0) {
576 Handle<SharedFunctionInfo> shared(info_->shared_info());
577 Label no_deopt;
578 __ pushfd();
579 __ push(eax);
580 __ push(ebx);
581 __ mov(ebx, shared);
582 __ mov(eax, FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset));
583 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000584 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585 if (FLAG_trap_on_deopt) __ int3();
586 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
587 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
588 __ pop(ebx);
589 __ pop(eax);
590 __ popfd();
591 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
592
593 __ bind(&no_deopt);
594 __ mov(FieldOperand(ebx, SharedFunctionInfo::kDeoptCounterOffset), eax);
595 __ pop(ebx);
596 __ pop(eax);
597 __ popfd();
598 }
599
600 if (cc == no_condition) {
601 if (FLAG_trap_on_deopt) __ int3();
602 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
603 } else {
604 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000605 Label done;
606 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000607 __ int3();
608 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
609 __ bind(&done);
610 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612 }
613 }
614}
615
616
617void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
618 int length = deoptimizations_.length();
619 if (length == 0) return;
620 ASSERT(FLAG_deopt);
621 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000623
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000624 Handle<ByteArray> translations = translations_.CreateByteArray();
625 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000626 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
627
628 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000630 for (int i = 0; i < deoptimization_literals_.length(); i++) {
631 literals->set(i, *deoptimization_literals_[i]);
632 }
633 data->SetLiteralArray(*literals);
634
635 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
636 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
637
638 // Populate the deoptimization entries.
639 for (int i = 0; i < length; i++) {
640 LEnvironment* env = deoptimizations_[i];
641 data->SetAstId(i, Smi::FromInt(env->ast_id()));
642 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
643 data->SetArgumentsStackHeight(i,
644 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000645 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 }
647 code->set_deoptimization_data(*data);
648}
649
650
651int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
652 int result = deoptimization_literals_.length();
653 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
654 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
655 }
656 deoptimization_literals_.Add(literal);
657 return result;
658}
659
660
661void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
662 ASSERT(deoptimization_literals_.length() == 0);
663
664 const ZoneList<Handle<JSFunction> >* inlined_closures =
665 chunk()->inlined_closures();
666
667 for (int i = 0, length = inlined_closures->length();
668 i < length;
669 i++) {
670 DefineDeoptimizationLiteral(inlined_closures->at(i));
671 }
672
673 inlined_function_count_ = deoptimization_literals_.length();
674}
675
676
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000677void LCodeGen::RecordSafepointWithLazyDeopt(
678 LInstruction* instr, SafepointMode safepoint_mode) {
679 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
680 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
681 } else {
682 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
683 RecordSafepointWithRegisters(
684 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
685 }
686}
687
688
ager@chromium.org378b34e2011-01-28 08:04:38 +0000689void LCodeGen::RecordSafepoint(
690 LPointerMap* pointers,
691 Safepoint::Kind kind,
692 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000693 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000694 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000696 Safepoint safepoint =
697 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000698 for (int i = 0; i < operands->length(); i++) {
699 LOperand* pointer = operands->at(i);
700 if (pointer->IsStackSlot()) {
701 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000702 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
703 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000704 }
705 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000706}
707
708
709void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000710 Safepoint::DeoptMode mode) {
711 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000712}
713
714
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000715void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000716 LPointerMap empty_pointers(RelocInfo::kNoPosition);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000717 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000718}
719
720
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000721void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
722 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000723 Safepoint::DeoptMode mode) {
724 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000725}
726
727
728void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000729 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000730 masm()->positions_recorder()->RecordPosition(position);
731}
732
733
734void LCodeGen::DoLabel(LLabel* label) {
735 if (label->is_loop_header()) {
736 Comment(";;; B%d - LOOP entry", label->block_id());
737 } else {
738 Comment(";;; B%d", label->block_id());
739 }
740 __ bind(label->label());
741 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000742 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000743}
744
745
746void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000747 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000748}
749
750
751void LCodeGen::DoGap(LGap* gap) {
752 for (int i = LGap::FIRST_INNER_POSITION;
753 i <= LGap::LAST_INNER_POSITION;
754 i++) {
755 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
756 LParallelMove* move = gap->GetParallelMove(inner_pos);
757 if (move != NULL) DoParallelMove(move);
758 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000759}
760
761
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000762void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
763 DoGap(instr);
764}
765
766
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000767void LCodeGen::DoParameter(LParameter* instr) {
768 // Nothing to do.
769}
770
771
772void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000773 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000774 ASSERT(ToRegister(instr->result()).is(eax));
775 switch (instr->hydrogen()->major_key()) {
776 case CodeStub::RegExpConstructResult: {
777 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000778 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000779 break;
780 }
781 case CodeStub::RegExpExec: {
782 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000783 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000784 break;
785 }
786 case CodeStub::SubString: {
787 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000788 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789 break;
790 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000791 case CodeStub::NumberToString: {
792 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000793 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000794 break;
795 }
796 case CodeStub::StringAdd: {
797 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000798 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000799 break;
800 }
801 case CodeStub::StringCompare: {
802 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000803 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000804 break;
805 }
806 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +0000807 TranscendentalCacheStub stub(instr->transcendental_type(),
808 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000809 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000810 break;
811 }
812 default:
813 UNREACHABLE();
814 }
815}
816
817
818void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
819 // Nothing to do.
820}
821
822
823void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000824 if (instr->hydrogen()->HasPowerOf2Divisor()) {
825 Register dividend = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000826
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000827 int32_t divisor =
828 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000829
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000830 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000831
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000832 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000833 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000834 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000835 __ neg(dividend);
836 __ and_(dividend, divisor - 1);
837 __ neg(dividend);
838 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000839 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000840 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +0000841 } else {
842 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000843 }
844 __ bind(&positive_dividend);
845 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000846 __ bind(&done);
847 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000848 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000849 Register left_reg = ToRegister(instr->InputAt(0));
850 Register right_reg = ToRegister(instr->InputAt(1));
851 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000852
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000853 ASSERT(left_reg.is(eax));
854 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000855 ASSERT(!right_reg.is(eax));
856 ASSERT(!right_reg.is(edx));
857
858 // Check for x % 0.
859 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000860 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000861 DeoptimizeIf(zero, instr->environment());
862 }
863
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000864 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000865 __ j(zero, &remainder_eq_dividend, Label::kNear);
866 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000867
868 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000869 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000870 // The sign of the divisor doesn't matter.
871 __ neg(right_reg);
872
873 __ bind(&both_positive);
874 // If the dividend is smaller than the nonnegative
875 // divisor, the dividend is the result.
876 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000877 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000878
879 // Check if the divisor is a PowerOfTwo integer.
880 Register scratch = ToRegister(instr->TempAt(0));
881 __ mov(scratch, right_reg);
882 __ sub(Operand(scratch), Immediate(1));
883 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000884 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000885 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000886 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000887
888 __ bind(&do_subtraction);
889 const int kUnfolds = 3;
890 // Try a few subtractions of the dividend.
891 __ mov(scratch, left_reg);
892 for (int i = 0; i < kUnfolds; i++) {
893 // Reduce the dividend by the divisor.
894 __ sub(left_reg, Operand(right_reg));
895 // Check if the dividend is less than the divisor.
896 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000897 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000898 }
899 __ mov(left_reg, scratch);
900
901 // Slow case, using idiv instruction.
902 __ bind(&slow);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000903 // Sign extend to edx.
904 __ cdq();
905
906 // Check for (0 % -x) that will produce negative zero.
907 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000908 Label positive_left;
909 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000910 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000911 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000912 __ idiv(right_reg);
913
914 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000915 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000916 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000917
918 DeoptimizeIf(no_condition, instr->environment());
919 __ bind(&positive_left);
920 __ idiv(right_reg);
921 __ bind(&done);
922 } else {
923 __ idiv(right_reg);
924 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000925 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000926
927 __ bind(&remainder_eq_dividend);
928 __ mov(result_reg, left_reg);
929
930 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000931 }
932}
933
934
935void LCodeGen::DoDivI(LDivI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000936 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000937 ASSERT(ToRegister(instr->result()).is(eax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000938 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
939 ASSERT(!ToRegister(instr->InputAt(1)).is(eax));
940 ASSERT(!ToRegister(instr->InputAt(1)).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000941
942 Register left_reg = eax;
943
944 // Check for x / 0.
945 Register right_reg = ToRegister(right);
946 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
947 __ test(right_reg, ToOperand(right));
948 DeoptimizeIf(zero, instr->environment());
949 }
950
951 // Check for (0 / -x) that will produce negative zero.
952 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000953 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000954 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000955 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000956 __ test(right_reg, ToOperand(right));
957 DeoptimizeIf(sign, instr->environment());
958 __ bind(&left_not_zero);
959 }
960
961 // Check for (-kMinInt / -1).
962 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000963 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000964 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000965 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000966 __ cmp(right_reg, -1);
967 DeoptimizeIf(zero, instr->environment());
968 __ bind(&left_not_min_int);
969 }
970
971 // Sign extend to edx.
972 __ cdq();
973 __ idiv(right_reg);
974
975 // Deoptimize if remainder is not 0.
976 __ test(edx, Operand(edx));
977 DeoptimizeIf(not_zero, instr->environment());
978}
979
980
981void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000982 Register left = ToRegister(instr->InputAt(0));
983 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000984
985 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000986 __ mov(ToRegister(instr->TempAt(0)), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000987 }
988
989 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +0000990 // Try strength reductions on the multiplication.
991 // All replacement instructions are at most as long as the imul
992 // and have better latency.
993 int constant = ToInteger32(LConstantOperand::cast(right));
994 if (constant == -1) {
995 __ neg(left);
996 } else if (constant == 0) {
997 __ xor_(left, Operand(left));
998 } else if (constant == 2) {
999 __ add(left, Operand(left));
1000 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1001 // If we know that the multiplication can't overflow, it's safe to
1002 // use instructions that don't set the overflow flag for the
1003 // multiplication.
1004 switch (constant) {
1005 case 1:
1006 // Do nothing.
1007 break;
1008 case 3:
1009 __ lea(left, Operand(left, left, times_2, 0));
1010 break;
1011 case 4:
1012 __ shl(left, 2);
1013 break;
1014 case 5:
1015 __ lea(left, Operand(left, left, times_4, 0));
1016 break;
1017 case 8:
1018 __ shl(left, 3);
1019 break;
1020 case 9:
1021 __ lea(left, Operand(left, left, times_8, 0));
1022 break;
1023 case 16:
1024 __ shl(left, 4);
1025 break;
1026 default:
1027 __ imul(left, left, constant);
1028 break;
1029 }
1030 } else {
1031 __ imul(left, left, constant);
1032 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033 } else {
1034 __ imul(left, ToOperand(right));
1035 }
1036
1037 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1038 DeoptimizeIf(overflow, instr->environment());
1039 }
1040
1041 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1042 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001043 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001044 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001045 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001046 if (right->IsConstantOperand()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001047 if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001048 DeoptimizeIf(no_condition, instr->environment());
1049 }
1050 } else {
1051 // Test the non-zero operand for negative sign.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001052 __ or_(ToRegister(instr->TempAt(0)), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001053 DeoptimizeIf(sign, instr->environment());
1054 }
1055 __ bind(&done);
1056 }
1057}
1058
1059
1060void LCodeGen::DoBitI(LBitI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001061 LOperand* left = instr->InputAt(0);
1062 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001063 ASSERT(left->Equals(instr->result()));
1064 ASSERT(left->IsRegister());
1065
1066 if (right->IsConstantOperand()) {
1067 int right_operand = ToInteger32(LConstantOperand::cast(right));
1068 switch (instr->op()) {
1069 case Token::BIT_AND:
1070 __ and_(ToRegister(left), right_operand);
1071 break;
1072 case Token::BIT_OR:
1073 __ or_(ToRegister(left), right_operand);
1074 break;
1075 case Token::BIT_XOR:
1076 __ xor_(ToRegister(left), right_operand);
1077 break;
1078 default:
1079 UNREACHABLE();
1080 break;
1081 }
1082 } else {
1083 switch (instr->op()) {
1084 case Token::BIT_AND:
1085 __ and_(ToRegister(left), ToOperand(right));
1086 break;
1087 case Token::BIT_OR:
1088 __ or_(ToRegister(left), ToOperand(right));
1089 break;
1090 case Token::BIT_XOR:
1091 __ xor_(ToRegister(left), ToOperand(right));
1092 break;
1093 default:
1094 UNREACHABLE();
1095 break;
1096 }
1097 }
1098}
1099
1100
1101void LCodeGen::DoShiftI(LShiftI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001102 LOperand* left = instr->InputAt(0);
1103 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001104 ASSERT(left->Equals(instr->result()));
1105 ASSERT(left->IsRegister());
1106 if (right->IsRegister()) {
1107 ASSERT(ToRegister(right).is(ecx));
1108
1109 switch (instr->op()) {
1110 case Token::SAR:
1111 __ sar_cl(ToRegister(left));
1112 break;
1113 case Token::SHR:
1114 __ shr_cl(ToRegister(left));
1115 if (instr->can_deopt()) {
1116 __ test(ToRegister(left), Immediate(0x80000000));
1117 DeoptimizeIf(not_zero, instr->environment());
1118 }
1119 break;
1120 case Token::SHL:
1121 __ shl_cl(ToRegister(left));
1122 break;
1123 default:
1124 UNREACHABLE();
1125 break;
1126 }
1127 } else {
1128 int value = ToInteger32(LConstantOperand::cast(right));
1129 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1130 switch (instr->op()) {
1131 case Token::SAR:
1132 if (shift_count != 0) {
1133 __ sar(ToRegister(left), shift_count);
1134 }
1135 break;
1136 case Token::SHR:
1137 if (shift_count == 0 && instr->can_deopt()) {
1138 __ test(ToRegister(left), Immediate(0x80000000));
1139 DeoptimizeIf(not_zero, instr->environment());
1140 } else {
1141 __ shr(ToRegister(left), shift_count);
1142 }
1143 break;
1144 case Token::SHL:
1145 if (shift_count != 0) {
1146 __ shl(ToRegister(left), shift_count);
1147 }
1148 break;
1149 default:
1150 UNREACHABLE();
1151 break;
1152 }
1153 }
1154}
1155
1156
1157void LCodeGen::DoSubI(LSubI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001158 LOperand* left = instr->InputAt(0);
1159 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001160 ASSERT(left->Equals(instr->result()));
1161
1162 if (right->IsConstantOperand()) {
1163 __ sub(ToOperand(left), ToImmediate(right));
1164 } else {
1165 __ sub(ToRegister(left), ToOperand(right));
1166 }
1167 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1168 DeoptimizeIf(overflow, instr->environment());
1169 }
1170}
1171
1172
1173void LCodeGen::DoConstantI(LConstantI* instr) {
1174 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001175 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001176}
1177
1178
1179void LCodeGen::DoConstantD(LConstantD* instr) {
1180 ASSERT(instr->result()->IsDoubleRegister());
1181 XMMRegister res = ToDoubleRegister(instr->result());
1182 double v = instr->value();
1183 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1184 // do so if the constant is -0.0.
1185 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001186 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001187 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001188 Register temp = ToRegister(instr->TempAt(0));
1189 uint64_t int_val = BitCast<uint64_t, double>(v);
1190 int32_t lower = static_cast<int32_t>(int_val);
1191 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001192 if (CpuFeatures::IsSupported(SSE4_1)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001193 CpuFeatures::Scope scope(SSE4_1);
1194 if (lower != 0) {
1195 __ Set(temp, Immediate(lower));
1196 __ movd(res, Operand(temp));
1197 __ Set(temp, Immediate(upper));
1198 __ pinsrd(res, Operand(temp), 1);
1199 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001200 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001201 __ Set(temp, Immediate(upper));
1202 __ pinsrd(res, Operand(temp), 1);
1203 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001204 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001205 __ Set(temp, Immediate(upper));
1206 __ movd(res, Operand(temp));
1207 __ psllq(res, 32);
1208 if (lower != 0) {
1209 __ Set(temp, Immediate(lower));
1210 __ movd(xmm0, Operand(temp));
1211 __ por(res, xmm0);
1212 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001213 }
1214 }
1215}
1216
1217
1218void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001219 Register reg = ToRegister(instr->result());
1220 Handle<Object> handle = instr->value();
1221 if (handle->IsHeapObject()) {
1222 LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
1223 } else {
1224 __ Set(reg, Immediate(handle));
1225 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001226}
1227
1228
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001229void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001230 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001231 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001232 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1233}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001234
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001235
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001236void LCodeGen::DoFixedArrayBaseLength(
1237 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001238 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001239 Register array = ToRegister(instr->InputAt(0));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001240 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001241}
1242
1243
whesse@chromium.org7b260152011-06-20 15:33:18 +00001244void LCodeGen::DoElementsKind(LElementsKind* instr) {
1245 Register result = ToRegister(instr->result());
1246 Register input = ToRegister(instr->InputAt(0));
1247
1248 // Load map into |result|.
1249 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1250 // Load the map's "bit field 2" into |result|. We only need the first byte,
1251 // but the following masking takes care of that anyway.
1252 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1253 // Retrieve elements_kind from bit field 2.
1254 __ and_(result, Map::kElementsKindMask);
1255 __ shr(result, Map::kElementsKindShift);
1256}
1257
1258
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001259void LCodeGen::DoValueOf(LValueOf* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001260 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001261 Register result = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001262 Register map = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001263 ASSERT(input.is(result));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001264 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001265 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001266 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001267
1268 // If the object is not a value type, return the object.
1269 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001270 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001271 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1272
1273 __ bind(&done);
1274}
1275
1276
1277void LCodeGen::DoBitNotI(LBitNotI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001278 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001279 ASSERT(input->Equals(instr->result()));
1280 __ not_(ToRegister(input));
1281}
1282
1283
1284void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001285 __ push(ToOperand(instr->value()));
1286 ASSERT(ToRegister(instr->context()).is(esi));
1287 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001288
1289 if (FLAG_debug_code) {
1290 Comment("Unreachable code.");
1291 __ int3();
1292 }
1293}
1294
1295
1296void LCodeGen::DoAddI(LAddI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001297 LOperand* left = instr->InputAt(0);
1298 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001299 ASSERT(left->Equals(instr->result()));
1300
1301 if (right->IsConstantOperand()) {
1302 __ add(ToOperand(left), ToImmediate(right));
1303 } else {
1304 __ add(ToRegister(left), ToOperand(right));
1305 }
1306
1307 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1308 DeoptimizeIf(overflow, instr->environment());
1309 }
1310}
1311
1312
1313void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001314 XMMRegister left = ToDoubleRegister(instr->InputAt(0));
1315 XMMRegister right = ToDoubleRegister(instr->InputAt(1));
1316 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001317 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001318 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001319 switch (instr->op()) {
1320 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001321 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001322 break;
1323 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001324 __ subsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001325 break;
1326 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001327 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001328 break;
1329 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001330 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001331 break;
1332 case Token::MOD: {
1333 // Pass two doubles as arguments on the stack.
1334 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001335 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1336 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001337 __ CallCFunction(
1338 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1339 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001340
1341 // Return value is in st(0) on ia32.
1342 // Store it into the (fixed) result register.
1343 __ sub(Operand(esp), Immediate(kDoubleSize));
1344 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001346 __ add(Operand(esp), Immediate(kDoubleSize));
1347 break;
1348 }
1349 default:
1350 UNREACHABLE();
1351 break;
1352 }
1353}
1354
1355
1356void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001357 ASSERT(ToRegister(instr->context()).is(esi));
1358 ASSERT(ToRegister(instr->left()).is(edx));
1359 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001360 ASSERT(ToRegister(instr->result()).is(eax));
1361
danno@chromium.org40cb8782011-05-25 07:58:50 +00001362 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001363 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001364 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001365}
1366
1367
1368int LCodeGen::GetNextEmittedBlock(int block) {
1369 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1370 LLabel* label = chunk_->GetLabel(i);
1371 if (!label->HasReplacement()) return i;
1372 }
1373 return -1;
1374}
1375
1376
1377void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1378 int next_block = GetNextEmittedBlock(current_block_);
1379 right_block = chunk_->LookupDestination(right_block);
1380 left_block = chunk_->LookupDestination(left_block);
1381
1382 if (right_block == left_block) {
1383 EmitGoto(left_block);
1384 } else if (left_block == next_block) {
1385 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1386 } else if (right_block == next_block) {
1387 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1388 } else {
1389 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1390 __ jmp(chunk_->GetAssemblyLabel(right_block));
1391 }
1392}
1393
1394
1395void LCodeGen::DoBranch(LBranch* instr) {
1396 int true_block = chunk_->LookupDestination(instr->true_block_id());
1397 int false_block = chunk_->LookupDestination(instr->false_block_id());
1398
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001399 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001400 if (r.IsInteger32()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001401 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001402 __ test(reg, Operand(reg));
1403 EmitBranch(true_block, false_block, not_zero);
1404 } else if (r.IsDouble()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001405 XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001406 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001407 __ ucomisd(reg, xmm0);
1408 EmitBranch(true_block, false_block, not_equal);
1409 } else {
1410 ASSERT(r.IsTagged());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001411 Register reg = ToRegister(instr->InputAt(0));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001412 HType type = instr->hydrogen()->value()->type();
1413 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001414 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001415 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001416 } else if (type.IsSmi()) {
1417 __ test(reg, Operand(reg));
1418 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001419 } else {
1420 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1421 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1422
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001423 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1424 // Avoid deopts in the case where we've never executed this path before.
1425 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001426
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001427 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1428 // undefined -> false.
1429 __ cmp(reg, factory()->undefined_value());
1430 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001431 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001432 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1433 // true -> true.
1434 __ cmp(reg, factory()->true_value());
1435 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001436 // false -> false.
1437 __ cmp(reg, factory()->false_value());
1438 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001439 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001440 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1441 // 'null' -> false.
1442 __ cmp(reg, factory()->null_value());
1443 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001444 }
1445
1446 if (expected.Contains(ToBooleanStub::SMI)) {
1447 // Smis: 0 -> false, all other -> true.
1448 __ test(reg, Operand(reg));
1449 __ j(equal, false_label);
1450 __ JumpIfSmi(reg, true_label);
1451 } else if (expected.NeedsMap()) {
1452 // If we need a map later and have a Smi -> deopt.
1453 __ test(reg, Immediate(kSmiTagMask));
1454 DeoptimizeIf(zero, instr->environment());
1455 }
1456
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001457 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001458 if (expected.NeedsMap()) {
1459 map = ToRegister(instr->TempAt(0));
1460 ASSERT(!map.is(reg));
1461 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001462
1463 if (expected.CanBeUndetectable()) {
1464 // Undetectable -> false.
1465 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
1466 1 << Map::kIsUndetectable);
1467 __ j(not_zero, false_label);
1468 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001469 }
1470
1471 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1472 // spec object -> true.
1473 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
1474 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001475 }
1476
1477 if (expected.Contains(ToBooleanStub::STRING)) {
1478 // String value -> false iff empty.
1479 Label not_string;
1480 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1481 __ j(above_equal, &not_string, Label::kNear);
1482 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1483 __ j(not_zero, true_label);
1484 __ jmp(false_label);
1485 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001486 }
1487
1488 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1489 // heap number -> false iff +0, -0, or NaN.
1490 Label not_heap_number;
1491 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
1492 factory()->heap_number_map());
1493 __ j(not_equal, &not_heap_number, Label::kNear);
1494 __ fldz();
1495 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
1496 __ FCmp();
1497 __ j(zero, false_label);
1498 __ jmp(true_label);
1499 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001500 }
1501
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001502 // We've seen something for the first time -> deopt.
1503 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001504 }
1505 }
1506}
1507
1508
ager@chromium.org04921a82011-06-27 13:21:41 +00001509void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001510 block = chunk_->LookupDestination(block);
1511 int next_block = GetNextEmittedBlock(current_block_);
1512 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001513 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001514 }
1515}
1516
1517
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001518void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001519 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520}
1521
1522
1523Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1524 Condition cond = no_condition;
1525 switch (op) {
1526 case Token::EQ:
1527 case Token::EQ_STRICT:
1528 cond = equal;
1529 break;
1530 case Token::LT:
1531 cond = is_unsigned ? below : less;
1532 break;
1533 case Token::GT:
1534 cond = is_unsigned ? above : greater;
1535 break;
1536 case Token::LTE:
1537 cond = is_unsigned ? below_equal : less_equal;
1538 break;
1539 case Token::GTE:
1540 cond = is_unsigned ? above_equal : greater_equal;
1541 break;
1542 case Token::IN:
1543 case Token::INSTANCEOF:
1544 default:
1545 UNREACHABLE();
1546 }
1547 return cond;
1548}
1549
1550
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001551void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001552 LOperand* left = instr->InputAt(0);
1553 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001554 int false_block = chunk_->LookupDestination(instr->false_block_id());
1555 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001556 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001557
1558 if (left->IsConstantOperand() && right->IsConstantOperand()) {
1559 // We can statically evaluate the comparison.
1560 double left_val = ToDouble(LConstantOperand::cast(left));
1561 double right_val = ToDouble(LConstantOperand::cast(right));
1562 int next_block =
1563 EvalComparison(instr->op(), left_val, right_val) ? true_block
1564 : false_block;
1565 EmitGoto(next_block);
1566 } else {
1567 if (instr->is_double()) {
1568 // Don't base result on EFLAGS when a NaN is involved. Instead
1569 // jump to the false block.
1570 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
1571 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
1572 } else {
1573 if (right->IsConstantOperand()) {
1574 __ cmp(ToRegister(left), ToImmediate(right));
1575 } else if (left->IsConstantOperand()) {
1576 __ cmp(ToOperand(right), ToImmediate(left));
1577 // We transposed the operands. Reverse the condition.
1578 cc = ReverseCondition(cc);
1579 } else {
1580 __ cmp(ToRegister(left), ToOperand(right));
1581 }
1582 }
1583 EmitBranch(true_block, false_block, cc);
1584 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585}
1586
1587
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001588void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001589 Register left = ToRegister(instr->InputAt(0));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001590 Operand right = ToOperand(instr->InputAt(1));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001591 int false_block = chunk_->LookupDestination(instr->false_block_id());
1592 int true_block = chunk_->LookupDestination(instr->true_block_id());
1593
1594 __ cmp(left, Operand(right));
1595 EmitBranch(true_block, false_block, equal);
1596}
1597
1598
whesse@chromium.org7b260152011-06-20 15:33:18 +00001599void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
1600 Register left = ToRegister(instr->InputAt(0));
1601 int true_block = chunk_->LookupDestination(instr->true_block_id());
1602 int false_block = chunk_->LookupDestination(instr->false_block_id());
1603
1604 __ cmp(left, instr->hydrogen()->right());
1605 EmitBranch(true_block, false_block, equal);
1606}
1607
1608
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001609void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001610 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001611 int false_block = chunk_->LookupDestination(instr->false_block_id());
1612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 // If the expression is known to be untagged or a smi, then it's definitely
1614 // not null, and it can't be a an undetectable object.
1615 if (instr->hydrogen()->representation().IsSpecialization() ||
1616 instr->hydrogen()->type().IsSmi()) {
1617 EmitGoto(false_block);
1618 return;
1619 }
1620
1621 int true_block = chunk_->LookupDestination(instr->true_block_id());
1622 Handle<Object> nil_value = instr->nil() == kNullValue ?
1623 factory()->null_value() :
1624 factory()->undefined_value();
1625 __ cmp(reg, nil_value);
1626 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001627 EmitBranch(true_block, false_block, equal);
1628 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
1630 factory()->undefined_value() :
1631 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001632 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1633 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1634 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001636 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001637 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001638 // Check for undetectable objects by looking in the bit field in
1639 // the map. The object has already been smi checked.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001640 Register scratch = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
1642 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
1643 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
1644 EmitBranch(true_block, false_block, not_zero);
1645 }
1646}
1647
1648
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001649Condition LCodeGen::EmitIsObject(Register input,
1650 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001651 Label* is_not_object,
1652 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001653 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001654
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001655 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001656 __ j(equal, is_object);
1657
1658 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
1659 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001660 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
1661 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001662 __ j(not_zero, is_not_object);
1663
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001664 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
1665 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001666 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001667 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001668 return below_equal;
1669}
1670
1671
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001672void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001673 Register reg = ToRegister(instr->InputAt(0));
1674 Register temp = ToRegister(instr->TempAt(0));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001675
1676 int true_block = chunk_->LookupDestination(instr->true_block_id());
1677 int false_block = chunk_->LookupDestination(instr->false_block_id());
1678 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1679 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1680
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001681 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001682
1683 EmitBranch(true_block, false_block, true_cond);
1684}
1685
1686
erikcorry0ad885c2011-11-21 13:51:57 +00001687Condition LCodeGen::EmitIsString(Register input,
1688 Register temp1,
1689 Label* is_not_string) {
1690 __ JumpIfSmi(input, is_not_string);
1691
1692 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
1693
1694 return cond;
1695}
1696
1697
1698void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
1699 Register reg = ToRegister(instr->InputAt(0));
1700 Register temp = ToRegister(instr->TempAt(0));
1701
1702 int true_block = chunk_->LookupDestination(instr->true_block_id());
1703 int false_block = chunk_->LookupDestination(instr->false_block_id());
1704 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1705
1706 Condition true_cond = EmitIsString(reg, temp, false_label);
1707
1708 EmitBranch(true_block, false_block, true_cond);
1709}
1710
1711
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001712void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001713 Operand input = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001714
1715 int true_block = chunk_->LookupDestination(instr->true_block_id());
1716 int false_block = chunk_->LookupDestination(instr->false_block_id());
1717
1718 __ test(input, Immediate(kSmiTagMask));
1719 EmitBranch(true_block, false_block, zero);
1720}
1721
1722
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001723void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1724 Register input = ToRegister(instr->InputAt(0));
1725 Register temp = ToRegister(instr->TempAt(0));
1726
1727 int true_block = chunk_->LookupDestination(instr->true_block_id());
1728 int false_block = chunk_->LookupDestination(instr->false_block_id());
1729
1730 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001731 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001732 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1733 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
1734 1 << Map::kIsUndetectable);
1735 EmitBranch(true_block, false_block, not_zero);
1736}
1737
1738
erikcorry0ad885c2011-11-21 13:51:57 +00001739static Condition ComputeCompareCondition(Token::Value op) {
1740 switch (op) {
1741 case Token::EQ_STRICT:
1742 case Token::EQ:
1743 return equal;
1744 case Token::LT:
1745 return less;
1746 case Token::GT:
1747 return greater;
1748 case Token::LTE:
1749 return less_equal;
1750 case Token::GTE:
1751 return greater_equal;
1752 default:
1753 UNREACHABLE();
1754 return no_condition;
1755 }
1756}
1757
1758
1759void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
1760 Token::Value op = instr->op();
1761 int true_block = chunk_->LookupDestination(instr->true_block_id());
1762 int false_block = chunk_->LookupDestination(instr->false_block_id());
1763
1764 Handle<Code> ic = CompareIC::GetUninitialized(op);
1765 CallCode(ic, RelocInfo::CODE_TARGET, instr);
1766
1767 Condition condition = ComputeCompareCondition(op);
1768 __ test(eax, Operand(eax));
1769
1770 EmitBranch(true_block, false_block, condition);
1771}
1772
1773
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001774static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001775 InstanceType from = instr->from();
1776 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001777 if (from == FIRST_TYPE) return to;
1778 ASSERT(from == to || to == LAST_TYPE);
1779 return from;
1780}
1781
1782
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001783static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001784 InstanceType from = instr->from();
1785 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 if (from == to) return equal;
1787 if (to == LAST_TYPE) return above_equal;
1788 if (from == FIRST_TYPE) return below_equal;
1789 UNREACHABLE();
1790 return equal;
1791}
1792
1793
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001794void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001795 Register input = ToRegister(instr->InputAt(0));
1796 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001797
1798 int true_block = chunk_->LookupDestination(instr->true_block_id());
1799 int false_block = chunk_->LookupDestination(instr->false_block_id());
1800
1801 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1802
whesse@chromium.org7b260152011-06-20 15:33:18 +00001803 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001804
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001805 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
1806 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001807}
1808
1809
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001810void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1811 Register input = ToRegister(instr->InputAt(0));
1812 Register result = ToRegister(instr->result());
1813
1814 if (FLAG_debug_code) {
1815 __ AbortIfNotString(input);
1816 }
1817
1818 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
1819 __ IndexFromHash(result, result);
1820}
1821
1822
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001823void LCodeGen::DoHasCachedArrayIndexAndBranch(
1824 LHasCachedArrayIndexAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001825 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001826
1827 int true_block = chunk_->LookupDestination(instr->true_block_id());
1828 int false_block = chunk_->LookupDestination(instr->false_block_id());
1829
1830 __ test(FieldOperand(input, String::kHashFieldOffset),
1831 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001832 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001833}
1834
1835
1836// Branches to a label or falls through with the answer in the z flag. Trashes
1837// the temp registers, but not the input. Only input and temp2 may alias.
1838void LCodeGen::EmitClassOfTest(Label* is_true,
1839 Label* is_false,
1840 Handle<String>class_name,
1841 Register input,
1842 Register temp,
1843 Register temp2) {
1844 ASSERT(!input.is(temp));
1845 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001846 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001847
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001848 if (class_name->IsEqualTo(CStrVector("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001849 // Assuming the following assertions, we can use the same compares to test
1850 // for both being a function type and being in the object type range.
1851 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
1852 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1853 FIRST_SPEC_OBJECT_TYPE + 1);
1854 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
1855 LAST_SPEC_OBJECT_TYPE - 1);
1856 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
1857 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
1858 __ j(below, is_false);
1859 __ j(equal, is_true);
1860 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
1861 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001862 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001863 // Faster code path to avoid two compares: subtract lower bound from the
1864 // actual type and do a signed compare with the width of the type range.
1865 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
1866 __ mov(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
1867 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1868 __ cmpb(Operand(temp2),
1869 static_cast<int8_t>(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
1870 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1871 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001872 }
1873
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001874 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001875 // Check if the constructor in the map is a function.
1876 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001877 // Objects with a non-function constructor have class 'Object'.
1878 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
1879 if (class_name->IsEqualTo(CStrVector("Object"))) {
1880 __ j(not_equal, is_true);
1881 } else {
1882 __ j(not_equal, is_false);
1883 }
1884
1885 // temp now contains the constructor function. Grab the
1886 // instance class name from there.
1887 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
1888 __ mov(temp, FieldOperand(temp,
1889 SharedFunctionInfo::kInstanceClassNameOffset));
1890 // The class name we are testing against is a symbol because it's a literal.
1891 // The name in the constructor is a symbol because of the way the context is
1892 // booted. This routine isn't expected to work for random API-created
1893 // classes and it doesn't have to because you can't access it with natives
1894 // syntax. Since both sides are symbols it is sufficient to use an identity
1895 // comparison.
1896 __ cmp(temp, class_name);
1897 // End with the answer in the z flag.
1898}
1899
1900
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001902 Register input = ToRegister(instr->InputAt(0));
1903 Register temp = ToRegister(instr->TempAt(0));
1904 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001905 if (input.is(temp)) {
1906 // Swap.
1907 Register swapper = temp;
1908 temp = temp2;
1909 temp2 = swapper;
1910 }
1911 Handle<String> class_name = instr->hydrogen()->class_name();
1912
1913 int true_block = chunk_->LookupDestination(instr->true_block_id());
1914 int false_block = chunk_->LookupDestination(instr->false_block_id());
1915
1916 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1917 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1918
1919 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
1920
1921 EmitBranch(true_block, false_block, equal);
1922}
1923
1924
1925void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001926 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001927 int true_block = instr->true_block_id();
1928 int false_block = instr->false_block_id();
1929
1930 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
1931 EmitBranch(true_block, false_block, equal);
1932}
1933
1934
1935void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001936 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001937 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001938 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001939 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001940
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001941 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001942 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001943 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001944 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001945 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001946 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001948 __ bind(&done);
1949}
1950
1951
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001952void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
1953 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
1954 public:
1955 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
1956 LInstanceOfKnownGlobal* instr)
1957 : LDeferredCode(codegen), instr_(instr) { }
1958 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001959 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001960 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001961 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001962 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001963 private:
1964 LInstanceOfKnownGlobal* instr_;
1965 Label map_check_;
1966 };
1967
1968 DeferredInstanceOfKnownGlobal* deferred;
1969 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
1970
1971 Label done, false_result;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001972 Register object = ToRegister(instr->InputAt(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001973 Register temp = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001974
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001975 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001976 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001977
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001978 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001979 // hole value will be patched to the last map/result pair generated by the
1980 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001981 Label cache_miss;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001982 Register map = ToRegister(instr->TempAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001983 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
1984 __ bind(deferred->map_check()); // Label for calculating code patching.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 __ cmp(map, factory()->the_hole_value()); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001986 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001988 __ jmp(&done);
1989
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001990 // The inlined call site cache did not match. Check for null and string
1991 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001992 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001993 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001995 __ j(equal, &false_result);
1996
1997 // String values are not instances of anything.
1998 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
1999 __ j(is_string, &false_result);
2000
2001 // Go to the deferred code.
2002 __ jmp(deferred->entry());
2003
2004 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002006
2007 // Here result has either true or false. Deferred code also produces true or
2008 // false object.
2009 __ bind(deferred->exit());
2010 __ bind(&done);
2011}
2012
2013
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002014void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2015 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002016 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002017
2018 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2019 flags = static_cast<InstanceofStub::Flags>(
2020 flags | InstanceofStub::kArgsInRegisters);
2021 flags = static_cast<InstanceofStub::Flags>(
2022 flags | InstanceofStub::kCallSiteInlineCheck);
2023 flags = static_cast<InstanceofStub::Flags>(
2024 flags | InstanceofStub::kReturnTrueFalseObject);
2025 InstanceofStub stub(flags);
2026
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002027 // Get the temp register reserved by the instruction. This needs to be a
2028 // register which is pushed last by PushSafepointRegisters as top of the
2029 // stack is used to pass the offset to the location of the map check to
2030 // the stub.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002031 Register temp = ToRegister(instr->TempAt(0));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002032 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002033 __ mov(InstanceofStub::right(), Immediate(instr->function()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002034 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002035 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002036 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002037 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002038 CallCodeGeneric(stub.GetCode(),
2039 RelocInfo::CODE_TARGET,
2040 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002041 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002042 ASSERT(instr->HasDeoptimizationEnvironment());
2043 LEnvironment* env = instr->deoptimization_environment();
2044 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2045
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002046 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002047 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002048}
2049
2050
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002051void LCodeGen::DoCmpT(LCmpT* instr) {
2052 Token::Value op = instr->op();
2053
2054 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002055 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002056
2057 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002058 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002060 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002061 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002062 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002063 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002064 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002065 __ bind(&done);
2066}
2067
2068
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002069void LCodeGen::DoReturn(LReturn* instr) {
2070 if (FLAG_trace) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002071 // Preserve the return value on the stack and rely on the runtime call
2072 // to return the value in the same register. We're leaving the code
2073 // managed by the register allocator and tearing down the frame, it's
2074 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002075 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002076 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002077 __ CallRuntime(Runtime::kTraceExit, 1);
2078 }
2079 __ mov(esp, ebp);
2080 __ pop(ebp);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002081 if (dynamic_frame_alignment_) {
2082 Label aligned;
2083 // Frame alignment marker (padding) is below arguments,
2084 // and receiver, so its return-address-relative offset is
2085 // (num_arguments + 2) words.
2086 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2087 Immediate(factory()->frame_alignment_marker()));
2088 __ j(not_equal, &aligned);
2089 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2090 __ bind(&aligned);
2091 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00002092 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002093}
2094
2095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002096void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002097 Register result = ToRegister(instr->result());
2098 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002099 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002100 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002101 DeoptimizeIf(equal, instr->environment());
2102 }
2103}
2104
2105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002106void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2107 ASSERT(ToRegister(instr->context()).is(esi));
2108 ASSERT(ToRegister(instr->global_object()).is(eax));
2109 ASSERT(ToRegister(instr->result()).is(eax));
2110
2111 __ mov(ecx, instr->name());
2112 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2113 RelocInfo::CODE_TARGET_CONTEXT;
2114 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002115 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002116}
2117
2118
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002119void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 Register object = ToRegister(instr->TempAt(0));
2121 Register address = ToRegister(instr->TempAt(1));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002122 Register value = ToRegister(instr->InputAt(0));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002123 ASSERT(!value.is(object));
2124 Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell());
2125
2126 int offset = JSGlobalPropertyCell::kValueOffset;
2127 __ mov(object, Immediate(cell_handle));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002128
2129 // If the cell we are storing to contains the hole it could have
2130 // been deleted from the property dictionary. In that case, we need
2131 // to update the property details in the property dictionary to mark
2132 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002133 if (instr->hydrogen()->RequiresHoleCheck()) {
2134 __ cmp(FieldOperand(object, offset), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002135 DeoptimizeIf(equal, instr->environment());
2136 }
2137
2138 // Store the value.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002139 __ mov(FieldOperand(object, offset), value);
2140
2141 // Cells are always in the remembered set.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002142 if (instr->hydrogen()->NeedsWriteBarrier()) {
2143 HType type = instr->hydrogen()->value()->type();
2144 SmiCheck check_needed =
2145 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
2146 __ RecordWriteField(object,
2147 offset,
2148 value,
2149 address,
2150 kSaveFPRegs,
2151 OMIT_REMEMBERED_SET,
2152 check_needed);
2153 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002154}
2155
2156
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002157void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2158 ASSERT(ToRegister(instr->context()).is(esi));
2159 ASSERT(ToRegister(instr->global_object()).is(edx));
2160 ASSERT(ToRegister(instr->value()).is(eax));
2161
2162 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002163 Handle<Code> ic = instr->strict_mode()
2164 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2165 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002166 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002167}
2168
2169
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002170void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002171 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002172 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002173 __ mov(result, ContextOperand(context, instr->slot_index()));
2174}
2175
2176
2177void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2178 Register context = ToRegister(instr->context());
2179 Register value = ToRegister(instr->value());
2180 __ mov(ContextOperand(context, instr->slot_index()), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002181 if (instr->hydrogen()->NeedsWriteBarrier()) {
2182 HType type = instr->hydrogen()->value()->type();
2183 SmiCheck check_needed =
2184 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002185 Register temp = ToRegister(instr->TempAt(0));
2186 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002187 __ RecordWriteContextSlot(context,
2188 offset,
2189 value,
2190 temp,
2191 kSaveFPRegs,
2192 EMIT_REMEMBERED_SET,
2193 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002194 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002195}
2196
2197
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002198void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002199 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002200 Register result = ToRegister(instr->result());
2201 if (instr->hydrogen()->is_in_object()) {
2202 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2203 } else {
2204 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2205 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2206 }
2207}
2208
2209
lrn@chromium.org1c092762011-05-09 09:42:16 +00002210void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2211 Register object,
2212 Handle<Map> type,
2213 Handle<String> name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002214 LookupResult lookup(isolate());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002215 type->LookupInDescriptors(NULL, *name, &lookup);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002216 ASSERT(lookup.IsProperty() &&
2217 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2218 if (lookup.type() == FIELD) {
2219 int index = lookup.GetLocalFieldIndexFromMap(*type);
2220 int offset = index * kPointerSize;
2221 if (index < 0) {
2222 // Negative property indices are in-object properties, indexed
2223 // from the end of the fixed part of the object.
2224 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2225 } else {
2226 // Non-negative property indices are in the properties array.
2227 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2228 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2229 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002230 } else {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002231 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
2232 LoadHeapObject(result, Handle<HeapObject>::cast(function));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002233 }
2234}
2235
2236
2237void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2238 Register object = ToRegister(instr->object());
2239 Register result = ToRegister(instr->result());
2240
2241 int map_count = instr->hydrogen()->types()->length();
2242 Handle<String> name = instr->hydrogen()->name();
2243 if (map_count == 0) {
2244 ASSERT(instr->hydrogen()->need_generic());
2245 __ mov(ecx, name);
2246 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002247 CallCode(ic, RelocInfo::CODE_TARGET, instr);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002248 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002249 Label done;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002250 for (int i = 0; i < map_count - 1; ++i) {
2251 Handle<Map> map = instr->hydrogen()->types()->at(i);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002252 Label next;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002253 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002254 __ j(not_equal, &next, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002255 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002256 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002257 __ bind(&next);
2258 }
2259 Handle<Map> map = instr->hydrogen()->types()->last();
2260 __ cmp(FieldOperand(object, HeapObject::kMapOffset), map);
2261 if (instr->hydrogen()->need_generic()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002262 Label generic;
2263 __ j(not_equal, &generic, Label::kNear);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002264 EmitLoadFieldOrConstantFunction(result, object, map, name);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002265 __ jmp(&done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002266 __ bind(&generic);
2267 __ mov(ecx, name);
2268 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002269 CallCode(ic, RelocInfo::CODE_TARGET, instr);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002270 } else {
2271 DeoptimizeIf(not_equal, instr->environment());
lrn@chromium.org1c092762011-05-09 09:42:16 +00002272 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002273 }
2274 __ bind(&done);
2275 }
2276}
2277
2278
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002280 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002281 ASSERT(ToRegister(instr->object()).is(eax));
2282 ASSERT(ToRegister(instr->result()).is(eax));
2283
2284 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002285 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002286 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002287}
2288
2289
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002290void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2291 Register function = ToRegister(instr->function());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002292 Register temp = ToRegister(instr->TempAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002293 Register result = ToRegister(instr->result());
2294
2295 // Check that the function really is a function.
2296 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2297 DeoptimizeIf(not_equal, instr->environment());
2298
2299 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002300 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002301 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2302 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002303 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002304
2305 // Get the prototype or initial map from the function.
2306 __ mov(result,
2307 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2308
2309 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002310 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002311 DeoptimizeIf(equal, instr->environment());
2312
2313 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002314 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002315 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002316 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002317
2318 // Get the prototype from the initial map.
2319 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002320 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002321
2322 // Non-instance prototype: Fetch prototype from constructor field
2323 // in the function's map.
2324 __ bind(&non_instance);
2325 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2326
2327 // All done.
2328 __ bind(&done);
2329}
2330
2331
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002332void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002333 Register result = ToRegister(instr->result());
2334 Register input = ToRegister(instr->InputAt(0));
2335 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002336 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002337 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002338 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002339 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002340 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002341 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002343 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002344 Register temp((result.is(eax)) ? ebx : eax);
2345 __ push(temp);
2346 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002347 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2348 __ and_(temp, Map::kElementsKindMask);
2349 __ shr(temp, Map::kElementsKindShift);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002350 __ cmp(temp, FAST_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002351 __ j(equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002352 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002353 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002354 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002355 __ j(less_equal, &ok, Label::kNear);
2356 __ bind(&fail);
2357 __ Abort("Check for fast or external elements failed.");
2358 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002359 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002360 __ bind(&done);
2361 }
2362}
2363
2364
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002365void LCodeGen::DoLoadExternalArrayPointer(
2366 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002367 Register result = ToRegister(instr->result());
2368 Register input = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002369 __ mov(result, FieldOperand(input,
2370 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002371}
2372
2373
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002374void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2375 Register arguments = ToRegister(instr->arguments());
2376 Register length = ToRegister(instr->length());
2377 Operand index = ToOperand(instr->index());
2378 Register result = ToRegister(instr->result());
2379
2380 __ sub(length, index);
2381 DeoptimizeIf(below_equal, instr->environment());
2382
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002383 // There are two words between the frame pointer and the last argument.
2384 // Subtracting from length accounts for one of them add one more.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002385 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
2386}
2387
2388
2389void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002390 Register result = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002391
2392 // Load the result.
danno@chromium.orgb6451162011-08-17 14:33:23 +00002393 __ mov(result,
2394 BuildFastArrayOperand(instr->elements(), instr->key(),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002395 FAST_ELEMENTS,
danno@chromium.orgb6451162011-08-17 14:33:23 +00002396 FixedArray::kHeaderSize - kHeapObjectTag));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002397
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002398 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002399 if (instr->hydrogen()->RequiresHoleCheck()) {
2400 __ cmp(result, factory()->the_hole_value());
2401 DeoptimizeIf(equal, instr->environment());
2402 }
2403}
2404
2405
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002406void LCodeGen::DoLoadKeyedFastDoubleElement(
2407 LLoadKeyedFastDoubleElement* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002408 XMMRegister result = ToDoubleRegister(instr->result());
2409
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002410 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2411 sizeof(kHoleNanLower32);
2412 Operand hole_check_operand = BuildFastArrayOperand(
2413 instr->elements(), instr->key(),
2414 FAST_DOUBLE_ELEMENTS,
2415 offset);
2416 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
2417 DeoptimizeIf(equal, instr->environment());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002418
2419 Operand double_load_operand = BuildFastArrayOperand(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002420 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002421 FixedDoubleArray::kHeaderSize - kHeapObjectTag);
2422 __ movdbl(result, double_load_operand);
2423}
2424
2425
2426Operand LCodeGen::BuildFastArrayOperand(
danno@chromium.orgb6451162011-08-17 14:33:23 +00002427 LOperand* elements_pointer,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002428 LOperand* key,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002429 ElementsKind elements_kind,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002430 uint32_t offset) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00002431 Register elements_pointer_reg = ToRegister(elements_pointer);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002432 int shift_size = ElementsKindToShiftSize(elements_kind);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002433 if (key->IsConstantOperand()) {
2434 int constant_value = ToInteger32(LConstantOperand::cast(key));
2435 if (constant_value & 0xF0000000) {
2436 Abort("array index constant value too big");
2437 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00002438 return Operand(elements_pointer_reg,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002439 constant_value * (1 << shift_size) + offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002440 } else {
2441 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
danno@chromium.orgb6451162011-08-17 14:33:23 +00002442 return Operand(elements_pointer_reg, ToRegister(key), scale_factor, offset);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002443 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002444}
2445
2446
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002447void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2448 LLoadKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002449 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002450 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
2451 instr->key(), elements_kind, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002452 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002453 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002454 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002455 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002456 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002457 __ movdbl(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002458 } else {
2459 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002460 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002461 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002462 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002463 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002464 case EXTERNAL_PIXEL_ELEMENTS:
2465 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002466 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002467 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002468 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002469 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002470 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002471 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002472 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002473 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002474 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002475 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002476 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002477 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002478 __ mov(result, operand);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002479 __ test(result, Operand(result));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002480 // TODO(danno): we could be more clever here, perhaps having a special
2481 // version of the stub that detects if the overflow case actually
2482 // happens, and generate code that returns a double rather than int.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002483 DeoptimizeIf(negative, instr->environment());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002484 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002485 case EXTERNAL_FLOAT_ELEMENTS:
2486 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002487 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002488 case FAST_ELEMENTS:
2489 case FAST_DOUBLE_ELEMENTS:
2490 case DICTIONARY_ELEMENTS:
2491 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002492 UNREACHABLE();
2493 break;
2494 }
2495 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002496}
2497
2498
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002499void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002500 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002501 ASSERT(ToRegister(instr->object()).is(edx));
2502 ASSERT(ToRegister(instr->key()).is(eax));
2503
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002504 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002505 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002506}
2507
2508
2509void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
2510 Register result = ToRegister(instr->result());
2511
2512 // Check for arguments adapter frame.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002513 Label done, adapted;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002514 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2515 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
2516 __ cmp(Operand(result),
2517 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002518 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002519
2520 // No arguments adaptor frame.
2521 __ mov(result, Operand(ebp));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002522 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002523
2524 // Arguments adaptor frame present.
2525 __ bind(&adapted);
2526 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2527
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002528 // Result is the frame pointer for the frame if not adapted and for the real
2529 // frame below the adaptor frame if adapted.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002530 __ bind(&done);
2531}
2532
2533
2534void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002535 Operand elem = ToOperand(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002536 Register result = ToRegister(instr->result());
2537
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002538 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002539
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002540 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002541 __ cmp(ebp, elem);
2542 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002543 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002544
2545 // Arguments adaptor frame present. Get argument length from there.
2546 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2547 __ mov(result, Operand(result,
2548 ArgumentsAdaptorFrameConstants::kLengthOffset));
2549 __ SmiUntag(result);
2550
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002551 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002552 __ bind(&done);
2553}
2554
2555
2556void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
2557 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002558 Register function = ToRegister(instr->function());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002559 Register length = ToRegister(instr->length());
2560 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002561 Register scratch = ToRegister(instr->TempAt(0));
2562 ASSERT(receiver.is(eax)); // Used for parameter count.
2563 ASSERT(function.is(edi)); // Required by InvokeFunction.
2564 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002565
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002566 // If the receiver is null or undefined, we have to pass the global
2567 // object as a receiver to normal functions. Values have to be
2568 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002569 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002570
2571 // Do not transform the receiver to object for strict mode
2572 // functions.
2573 __ mov(scratch,
2574 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
2575 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
2576 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
2577 __ j(not_equal, &receiver_ok, Label::kNear);
2578
2579 // Do not transform the receiver to object for builtins.
2580 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
2581 1 << SharedFunctionInfo::kNativeBitWithinByte);
2582 __ j(not_equal, &receiver_ok, Label::kNear);
2583
2584 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002585 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002586 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002587 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002588 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002589
2590 // The receiver should be a JS object.
2591 __ test(receiver, Immediate(kSmiTagMask));
2592 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002593 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002594 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002595 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002596
2597 __ bind(&global_object);
2598 // TODO(kmillikin): We have a hydrogen value for the global object. See
2599 // if it's better to use it than to explicitly fetch it from the context
2600 // here.
2601 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
2602 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002603 __ mov(receiver,
2604 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002605 __ bind(&receiver_ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002606
2607 // Copy the arguments to this function possibly from the
2608 // adaptor frame below it.
2609 const uint32_t kArgumentsLimit = 1 * KB;
2610 __ cmp(length, kArgumentsLimit);
2611 DeoptimizeIf(above, instr->environment());
2612
2613 __ push(receiver);
2614 __ mov(receiver, length);
2615
2616 // Loop through the arguments pushing them onto the execution
2617 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002618 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002619 // length is a small non-negative integer, due to the test above.
2620 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002621 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002622 __ bind(&loop);
2623 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
2624 __ dec(length);
2625 __ j(not_zero, &loop);
2626
2627 // Invoke the function.
2628 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002629 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2630 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002631 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002632 SafepointGenerator safepoint_generator(
2633 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00002634 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002635 __ InvokeFunction(function, actual, CALL_FUNCTION,
2636 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002637}
2638
2639
2640void LCodeGen::DoPushArgument(LPushArgument* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002641 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002642 if (argument->IsConstantOperand()) {
2643 __ push(ToImmediate(argument));
2644 } else {
2645 __ push(ToOperand(argument));
2646 }
2647}
2648
2649
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002650void LCodeGen::DoThisFunction(LThisFunction* instr) {
2651 Register result = ToRegister(instr->result());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002652 LoadHeapObject(result, instr->hydrogen()->closure());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002653}
2654
2655
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002656void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002657 Register result = ToRegister(instr->result());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002658 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002659}
2660
2661
2662void LCodeGen::DoOuterContext(LOuterContext* instr) {
2663 Register context = ToRegister(instr->context());
2664 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002665 __ mov(result,
2666 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002667}
2668
2669
2670void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2671 Register context = ToRegister(instr->context());
2672 Register result = ToRegister(instr->result());
2673 __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002674}
2675
2676
2677void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002678 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002679 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002680 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002681}
2682
2683
2684void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2685 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002686 LInstruction* instr,
2687 CallKind call_kind) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002688 // Change context if needed.
2689 bool change_context =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002690 (info()->closure()->context() != function->context()) ||
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002691 scope()->contains_with() ||
2692 (scope()->num_heap_slots() > 0);
2693 if (change_context) {
2694 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002695 } else {
2696 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002697 }
2698
2699 // Set eax to arguments count if adaption is not needed. Assumes that eax
2700 // is available to write to at this point.
2701 if (!function->NeedsArgumentsAdaption()) {
2702 __ mov(eax, arity);
2703 }
2704
2705 LPointerMap* pointers = instr->pointer_map();
2706 RecordPosition(pointers->position());
2707
2708 // Invoke function.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002709 __ SetCallKind(ecx, call_kind);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002710 if (*function == *info()->closure()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002711 __ CallSelf();
2712 } else {
2713 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
2714 }
2715
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002716 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002717}
2718
2719
2720void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2721 ASSERT(ToRegister(instr->result()).is(eax));
2722 __ mov(edi, instr->function());
danno@chromium.org40cb8782011-05-25 07:58:50 +00002723 CallKnownFunction(instr->function(),
2724 instr->arity(),
2725 instr,
2726 CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727}
2728
2729
2730void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002731 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002732 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002734 DeoptimizeIf(not_equal, instr->environment());
2735
2736 Label done;
2737 Register tmp = input_reg.is(eax) ? ecx : eax;
2738 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
2739
2740 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002741 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002742
2743 Label negative;
2744 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002745 // Check the sign of the argument. If the argument is positive, just
2746 // return it. We do not need to patch the stack since |input| and
2747 // |result| are the same register and |input| will be restored
2748 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002749 __ test(tmp, Immediate(HeapNumber::kSignMask));
2750 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002751 __ jmp(&done);
2752
2753 __ bind(&negative);
2754
2755 Label allocated, slow;
2756 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
2757 __ jmp(&allocated);
2758
2759 // Slow case: Call the runtime system to do the number allocation.
2760 __ bind(&slow);
2761
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002762 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
2763 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002764
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002765 // Set the pointer to the new heap number in tmp.
2766 if (!tmp.is(eax)) __ mov(tmp, eax);
2767
2768 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002769 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002770
2771 __ bind(&allocated);
2772 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
2773 __ and_(tmp2, ~HeapNumber::kSignMask);
2774 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
2775 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
2776 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002777 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002778
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002779 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002780}
2781
2782
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002783void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002784 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002785 __ test(input_reg, Operand(input_reg));
2786 Label is_positive;
2787 __ j(not_sign, &is_positive);
2788 __ neg(input_reg);
2789 __ test(input_reg, Operand(input_reg));
2790 DeoptimizeIf(negative, instr->environment());
2791 __ bind(&is_positive);
2792}
2793
2794
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002795void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
2796 // Class for deferred case.
2797 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2798 public:
2799 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2800 LUnaryMathOperation* instr)
2801 : LDeferredCode(codegen), instr_(instr) { }
2802 virtual void Generate() {
2803 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
2804 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002805 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002806 private:
2807 LUnaryMathOperation* instr_;
2808 };
2809
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002810 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002811 Representation r = instr->hydrogen()->value()->representation();
2812
2813 if (r.IsDouble()) {
2814 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002815 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002816 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002817 __ subsd(scratch, input_reg);
2818 __ pand(input_reg, scratch);
2819 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002820 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002821 } else { // Tagged case.
2822 DeferredMathAbsTaggedHeapNumber* deferred =
2823 new DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002824 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002826 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002827 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002828 __ bind(deferred->exit());
2829 }
2830}
2831
2832
2833void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
2834 XMMRegister xmm_scratch = xmm0;
2835 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002836 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002837
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002838 if (CpuFeatures::IsSupported(SSE4_1)) {
2839 CpuFeatures::Scope scope(SSE4_1);
2840 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2841 // Deoptimize on negative zero.
2842 Label non_zero;
2843 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
2844 __ ucomisd(input_reg, xmm_scratch);
2845 __ j(not_equal, &non_zero, Label::kNear);
2846 __ movmskpd(output_reg, input_reg);
2847 __ test(output_reg, Immediate(1));
2848 DeoptimizeIf(not_zero, instr->environment());
2849 __ bind(&non_zero);
2850 }
2851 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
2852 __ cvttsd2si(output_reg, Operand(xmm_scratch));
2853 // Overflow is signalled with minint.
2854 __ cmp(output_reg, 0x80000000u);
2855 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002856 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002857 Label done;
2858 // Deoptimize on negative numbers.
2859 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
2860 __ ucomisd(input_reg, xmm_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002861 DeoptimizeIf(below, instr->environment());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002862
2863 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2864 // Check for negative zero.
2865 Label positive_sign;
2866 __ j(above, &positive_sign, Label::kNear);
2867 __ movmskpd(output_reg, input_reg);
2868 __ test(output_reg, Immediate(1));
2869 DeoptimizeIf(not_zero, instr->environment());
2870 __ Set(output_reg, Immediate(0));
2871 __ jmp(&done, Label::kNear);
2872 __ bind(&positive_sign);
2873 }
2874
2875 // Use truncating instruction (OK because input is positive).
2876 __ cvttsd2si(output_reg, Operand(input_reg));
2877
2878 // Overflow is signalled with minint.
2879 __ cmp(output_reg, 0x80000000u);
2880 DeoptimizeIf(equal, instr->environment());
2881 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002882 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002883}
2884
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002885void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2886 XMMRegister xmm_scratch = xmm0;
2887 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002888 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002889
danno@chromium.org160a7b02011-04-18 15:51:38 +00002890 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002891 // xmm_scratch = 0.5
2892 ExternalReference one_half = ExternalReference::address_of_one_half();
2893 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00002894 __ ucomisd(xmm_scratch, input_reg);
2895 __ j(above, &below_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002896 // input = input + 0.5
2897 __ addsd(input_reg, xmm_scratch);
2898
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002899 // Compute Math.floor(value + 0.5).
2900 // Use truncating instruction (OK because input is positive).
2901 __ cvttsd2si(output_reg, Operand(input_reg));
2902
2903 // Overflow is signalled with minint.
2904 __ cmp(output_reg, 0x80000000u);
2905 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00002906 __ jmp(&done);
2907
2908 __ bind(&below_half);
2909
2910 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
2911 // we can ignore the difference between a result of -0 and +0.
2912 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
2913 // If the sign is positive, we return +0.
2914 __ movmskpd(output_reg, input_reg);
2915 __ test(output_reg, Immediate(1));
2916 DeoptimizeIf(not_zero, instr->environment());
2917 } else {
2918 // If the input is >= -0.5, we return +0.
2919 __ mov(output_reg, Immediate(0xBF000000));
2920 __ movd(xmm_scratch, Operand(output_reg));
2921 __ cvtss2sd(xmm_scratch, xmm_scratch);
2922 __ ucomisd(input_reg, xmm_scratch);
2923 DeoptimizeIf(below, instr->environment());
2924 }
2925 __ Set(output_reg, Immediate(0));
2926 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002927}
2928
2929
2930void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002931 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002932 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
2933 __ sqrtsd(input_reg, input_reg);
2934}
2935
2936
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002937void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
2938 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002939 XMMRegister input_reg = ToDoubleRegister(instr->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002940 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00002941 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002942 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002943 __ sqrtsd(input_reg, input_reg);
2944}
2945
2946
2947void LCodeGen::DoPower(LPower* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002948 LOperand* left = instr->InputAt(0);
2949 LOperand* right = instr->InputAt(1);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002950 DoubleRegister result_reg = ToDoubleRegister(instr->result());
2951 Representation exponent_type = instr->hydrogen()->right()->representation();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002952
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002953 if (exponent_type.IsDouble()) {
2954 // It is safe to use ebx directly since the instruction is marked
2955 // as a call.
2956 __ PrepareCallCFunction(4, ebx);
2957 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2958 __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002959 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2960 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002961 } else if (exponent_type.IsInteger32()) {
2962 // It is safe to use ebx directly since the instruction is marked
2963 // as a call.
2964 ASSERT(!ToRegister(right).is(ebx));
2965 __ PrepareCallCFunction(4, ebx);
2966 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2967 __ mov(Operand(esp, 1 * kDoubleSize), ToRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 __ CallCFunction(ExternalReference::power_double_int_function(isolate()),
2969 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002970 } else {
2971 ASSERT(exponent_type.IsTagged());
2972 CpuFeatures::Scope scope(SSE2);
2973 Register right_reg = ToRegister(right);
2974
2975 Label non_smi, call;
whesse@chromium.org7b260152011-06-20 15:33:18 +00002976 __ JumpIfNotSmi(right_reg, &non_smi);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002977 __ SmiUntag(right_reg);
2978 __ cvtsi2sd(result_reg, Operand(right_reg));
2979 __ jmp(&call);
2980
2981 __ bind(&non_smi);
2982 // It is safe to use ebx directly since the instruction is marked
2983 // as a call.
2984 ASSERT(!right_reg.is(ebx));
2985 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , ebx);
2986 DeoptimizeIf(not_equal, instr->environment());
2987 __ movdbl(result_reg, FieldOperand(right_reg, HeapNumber::kValueOffset));
2988
2989 __ bind(&call);
2990 __ PrepareCallCFunction(4, ebx);
2991 __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
2992 __ movdbl(Operand(esp, 1 * kDoubleSize), result_reg);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
2994 4);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002995 }
2996
2997 // Return value is in st(0) on ia32.
2998 // Store it into the (fixed) result register.
2999 __ sub(Operand(esp), Immediate(kDoubleSize));
3000 __ fstp_d(Operand(esp, 0));
3001 __ movdbl(result_reg, Operand(esp, 0));
3002 __ add(Operand(esp), Immediate(kDoubleSize));
3003}
3004
3005
3006void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003007 ASSERT(instr->value()->Equals(instr->result()));
3008 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003009 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003010 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003011 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003012 __ j(above, &positive, Label::kNear);
3013 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003014 ExternalReference nan =
3015 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003016 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003017 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003018 __ bind(&zero);
3019 __ push(Immediate(0xFFF00000));
3020 __ push(Immediate(0));
3021 __ movdbl(input_reg, Operand(esp, 0));
3022 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003023 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003024 __ bind(&positive);
3025 __ fldln2();
3026 __ sub(Operand(esp), Immediate(kDoubleSize));
3027 __ movdbl(Operand(esp, 0), input_reg);
3028 __ fld_d(Operand(esp, 0));
3029 __ fyl2x();
3030 __ fstp_d(Operand(esp, 0));
3031 __ movdbl(input_reg, Operand(esp, 0));
3032 __ add(Operand(esp), Immediate(kDoubleSize));
3033 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003034}
3035
3036
3037void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3038 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3039 TranscendentalCacheStub stub(TranscendentalCache::COS,
3040 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003041 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003042}
3043
3044
3045void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3046 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3047 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3048 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003049 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003050}
3051
3052
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003053void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3054 switch (instr->op()) {
3055 case kMathAbs:
3056 DoMathAbs(instr);
3057 break;
3058 case kMathFloor:
3059 DoMathFloor(instr);
3060 break;
3061 case kMathRound:
3062 DoMathRound(instr);
3063 break;
3064 case kMathSqrt:
3065 DoMathSqrt(instr);
3066 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003067 case kMathPowHalf:
3068 DoMathPowHalf(instr);
3069 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003070 case kMathCos:
3071 DoMathCos(instr);
3072 break;
3073 case kMathSin:
3074 DoMathSin(instr);
3075 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003076 case kMathLog:
3077 DoMathLog(instr);
3078 break;
3079
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003080 default:
3081 UNREACHABLE();
3082 }
3083}
3084
3085
danno@chromium.org160a7b02011-04-18 15:51:38 +00003086void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3087 ASSERT(ToRegister(instr->context()).is(esi));
3088 ASSERT(ToRegister(instr->function()).is(edi));
3089 ASSERT(instr->HasPointerMap());
3090 ASSERT(instr->HasDeoptimizationEnvironment());
3091 LPointerMap* pointers = instr->pointer_map();
danno@chromium.org160a7b02011-04-18 15:51:38 +00003092 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003093 SafepointGenerator generator(
3094 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003095 ParameterCount count(instr->arity());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003096 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003097}
3098
3099
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003100void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003101 ASSERT(ToRegister(instr->context()).is(esi));
3102 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003103 ASSERT(ToRegister(instr->result()).is(eax));
3104
3105 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003106 Handle<Code> ic =
3107 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003108 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003109}
3110
3111
3112void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003113 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003114 ASSERT(ToRegister(instr->result()).is(eax));
3115
3116 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003117 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3118 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003119 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003120 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003121 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003122}
3123
3124
3125void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003126 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003127 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003128 ASSERT(ToRegister(instr->result()).is(eax));
3129
3130 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003131 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003132 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003133}
3134
3135
3136void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003137 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003138 ASSERT(ToRegister(instr->result()).is(eax));
3139
3140 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003141 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3142 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003143 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003144 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003145 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003146}
3147
3148
3149void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3150 ASSERT(ToRegister(instr->result()).is(eax));
3151 __ mov(edi, instr->target());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003152 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003153}
3154
3155
3156void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003157 ASSERT(ToRegister(instr->context()).is(esi));
3158 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003159 ASSERT(ToRegister(instr->result()).is(eax));
3160
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003161 Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003162 __ Set(eax, Immediate(instr->arity()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003163 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003164}
3165
3166
3167void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003168 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003169}
3170
3171
3172void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
3173 Register object = ToRegister(instr->object());
3174 Register value = ToRegister(instr->value());
3175 int offset = instr->offset();
3176
3177 if (!instr->transition().is_null()) {
3178 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
3179 }
3180
3181 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003182 HType type = instr->hydrogen()->value()->type();
3183 SmiCheck check_needed =
3184 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003185 if (instr->is_in_object()) {
3186 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003187 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003188 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003189 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003190 __ RecordWriteField(object,
3191 offset,
3192 value,
3193 temp,
3194 kSaveFPRegs,
3195 EMIT_REMEMBERED_SET,
3196 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003197 }
3198 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003199 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003200 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
3201 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003202 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003203 // Update the write barrier for the properties array.
3204 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003205 __ RecordWriteField(temp,
3206 offset,
3207 value,
3208 object,
3209 kSaveFPRegs,
3210 EMIT_REMEMBERED_SET,
3211 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003212 }
3213 }
3214}
3215
3216
3217void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003218 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003219 ASSERT(ToRegister(instr->object()).is(edx));
3220 ASSERT(ToRegister(instr->value()).is(eax));
3221
3222 __ mov(ecx, instr->name());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003223 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003224 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3225 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003226 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003227}
3228
3229
3230void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
danno@chromium.orgb6451162011-08-17 14:33:23 +00003231 if (instr->index()->IsConstantOperand()) {
3232 __ cmp(ToOperand(instr->length()),
3233 ToImmediate(LConstantOperand::cast(instr->index())));
3234 DeoptimizeIf(below_equal, instr->environment());
3235 } else {
3236 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
3237 DeoptimizeIf(above_equal, instr->environment());
3238 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003239}
3240
3241
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003242void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3243 LStoreKeyedSpecializedArrayElement* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003244 ElementsKind elements_kind = instr->elements_kind();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003245 Operand operand(BuildFastArrayOperand(instr->external_pointer(),
3246 instr->key(), elements_kind, 0));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003247 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003248 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003249 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003250 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003251 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003252 } else {
3253 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003254 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003255 case EXTERNAL_PIXEL_ELEMENTS:
3256 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3257 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003258 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003260 case EXTERNAL_SHORT_ELEMENTS:
3261 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003262 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003263 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003264 case EXTERNAL_INT_ELEMENTS:
3265 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003266 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003267 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003268 case EXTERNAL_FLOAT_ELEMENTS:
3269 case EXTERNAL_DOUBLE_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003270 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003271 case FAST_ELEMENTS:
3272 case FAST_DOUBLE_ELEMENTS:
3273 case DICTIONARY_ELEMENTS:
3274 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003275 UNREACHABLE();
3276 break;
3277 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003278 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003279}
3280
3281
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003282void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
3283 Register value = ToRegister(instr->value());
3284 Register elements = ToRegister(instr->object());
3285 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3286
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003287 // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
3288 // conversion, so it deopts in that case.
3289 if (instr->hydrogen()->ValueNeedsSmiCheck()) {
3290 __ test(value, Immediate(kSmiTagMask));
3291 DeoptimizeIf(not_zero, instr->environment());
3292 }
3293
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294 // Do the store.
3295 if (instr->key()->IsConstantOperand()) {
3296 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3297 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3298 int offset =
3299 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3300 __ mov(FieldOperand(elements, offset), value);
3301 } else {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003302 __ mov(FieldOperand(elements,
3303 key,
3304 times_pointer_size,
3305 FixedArray::kHeaderSize),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003306 value);
3307 }
3308
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003309 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003310 HType type = instr->hydrogen()->value()->type();
3311 SmiCheck check_needed =
3312 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003313 // Compute address of modified element and store it into key register.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003314 __ lea(key,
3315 FieldOperand(elements,
3316 key,
3317 times_pointer_size,
3318 FixedArray::kHeaderSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003319 __ RecordWrite(elements,
3320 key,
3321 value,
3322 kSaveFPRegs,
3323 EMIT_REMEMBERED_SET,
3324 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003325 }
3326}
3327
3328
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003329void LCodeGen::DoStoreKeyedFastDoubleElement(
3330 LStoreKeyedFastDoubleElement* instr) {
3331 XMMRegister value = ToDoubleRegister(instr->value());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003332 Label have_value;
3333
3334 __ ucomisd(value, value);
3335 __ j(parity_odd, &have_value); // NaN.
3336
3337 ExternalReference canonical_nan_reference =
3338 ExternalReference::address_of_canonical_non_hole_nan();
3339 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
3340 __ bind(&have_value);
3341
3342 Operand double_store_operand = BuildFastArrayOperand(
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003343 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS,
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003344 FixedDoubleArray::kHeaderSize - kHeapObjectTag);
3345 __ movdbl(double_store_operand, value);
3346}
3347
3348
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003349void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003350 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351 ASSERT(ToRegister(instr->object()).is(edx));
3352 ASSERT(ToRegister(instr->key()).is(ecx));
3353 ASSERT(ToRegister(instr->value()).is(eax));
3354
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003355 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003356 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3357 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003358 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003359}
3360
3361
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003362void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
3363 Register object_reg = ToRegister(instr->object());
3364 Register new_map_reg = ToRegister(instr->new_map_reg());
3365
3366 Handle<Map> from_map = instr->original_map();
3367 Handle<Map> to_map = instr->transitioned_map();
3368 ElementsKind from_kind = from_map->elements_kind();
3369 ElementsKind to_kind = to_map->elements_kind();
3370
3371 Label not_applicable;
3372 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
3373 __ j(not_equal, &not_applicable);
3374 __ mov(new_map_reg, to_map);
3375 if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) {
3376 Register object_reg = ToRegister(instr->object());
3377 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
3378 // Write barrier.
3379 ASSERT_NE(instr->temp_reg(), NULL);
3380 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
3381 ToRegister(instr->temp_reg()), kDontSaveFPRegs);
3382 } else if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
3383 to_kind == FAST_DOUBLE_ELEMENTS) {
3384 Register fixed_object_reg = ToRegister(instr->temp_reg());
3385 ASSERT(fixed_object_reg.is(edx));
3386 ASSERT(new_map_reg.is(ebx));
3387 __ mov(fixed_object_reg, object_reg);
3388 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
3389 RelocInfo::CODE_TARGET, instr);
3390 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
3391 Register fixed_object_reg = ToRegister(instr->temp_reg());
3392 ASSERT(fixed_object_reg.is(edx));
3393 ASSERT(new_map_reg.is(ebx));
3394 __ mov(fixed_object_reg, object_reg);
3395 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
3396 RelocInfo::CODE_TARGET, instr);
3397 } else {
3398 UNREACHABLE();
3399 }
3400 __ bind(&not_applicable);
3401}
3402
3403
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003404void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3405 class DeferredStringCharCodeAt: public LDeferredCode {
3406 public:
3407 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3408 : LDeferredCode(codegen), instr_(instr) { }
3409 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003410 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003411 private:
3412 LStringCharCodeAt* instr_;
3413 };
3414
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003415 DeferredStringCharCodeAt* deferred =
3416 new DeferredStringCharCodeAt(this, instr);
3417
erikcorry0ad885c2011-11-21 13:51:57 +00003418 StringCharLoadGenerator::Generate(masm(),
3419 factory(),
3420 ToRegister(instr->string()),
3421 ToRegister(instr->index()),
3422 ToRegister(instr->result()),
3423 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003424 __ bind(deferred->exit());
3425}
3426
3427
3428void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3429 Register string = ToRegister(instr->string());
3430 Register result = ToRegister(instr->result());
3431
3432 // TODO(3095996): Get rid of this. For now, we need to make the
3433 // result register contain a valid pointer because it is already
3434 // contained in the register pointer map.
3435 __ Set(result, Immediate(0));
3436
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003437 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003438 __ push(string);
3439 // Push the index as a smi. This is safe because of the checks in
3440 // DoStringCharCodeAt above.
3441 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3442 if (instr->index()->IsConstantOperand()) {
3443 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3444 __ push(Immediate(Smi::FromInt(const_index)));
3445 } else {
3446 Register index = ToRegister(instr->index());
3447 __ SmiTag(index);
3448 __ push(index);
3449 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003450 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
3451 instr, instr->context());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003452 if (FLAG_debug_code) {
3453 __ AbortIfNotSmi(eax);
3454 }
3455 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003456 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003457}
3458
3459
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003460void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3461 class DeferredStringCharFromCode: public LDeferredCode {
3462 public:
3463 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3464 : LDeferredCode(codegen), instr_(instr) { }
3465 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003466 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003467 private:
3468 LStringCharFromCode* instr_;
3469 };
3470
3471 DeferredStringCharFromCode* deferred =
3472 new DeferredStringCharFromCode(this, instr);
3473
3474 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3475 Register char_code = ToRegister(instr->char_code());
3476 Register result = ToRegister(instr->result());
3477 ASSERT(!char_code.is(result));
3478
3479 __ cmp(char_code, String::kMaxAsciiCharCode);
3480 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003482 __ mov(result, FieldOperand(result,
3483 char_code, times_pointer_size,
3484 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003485 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003486 __ j(equal, deferred->entry());
3487 __ bind(deferred->exit());
3488}
3489
3490
3491void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3492 Register char_code = ToRegister(instr->char_code());
3493 Register result = ToRegister(instr->result());
3494
3495 // TODO(3095996): Get rid of this. For now, we need to make the
3496 // result register contain a valid pointer because it is already
3497 // contained in the register pointer map.
3498 __ Set(result, Immediate(0));
3499
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003500 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003501 __ SmiTag(char_code);
3502 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003503 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003504 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003505}
3506
3507
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003508void LCodeGen::DoStringLength(LStringLength* instr) {
3509 Register string = ToRegister(instr->string());
3510 Register result = ToRegister(instr->result());
3511 __ mov(result, FieldOperand(string, String::kLengthOffset));
3512}
3513
3514
danno@chromium.org160a7b02011-04-18 15:51:38 +00003515void LCodeGen::DoStringAdd(LStringAdd* instr) {
3516 if (instr->left()->IsConstantOperand()) {
3517 __ push(ToImmediate(instr->left()));
3518 } else {
3519 __ push(ToOperand(instr->left()));
3520 }
3521 if (instr->right()->IsConstantOperand()) {
3522 __ push(ToImmediate(instr->right()));
3523 } else {
3524 __ push(ToOperand(instr->right()));
3525 }
3526 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003527 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003528}
3529
3530
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003531void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003532 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003533 ASSERT(input->IsRegister() || input->IsStackSlot());
3534 LOperand* output = instr->result();
3535 ASSERT(output->IsDoubleRegister());
3536 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
3537}
3538
3539
3540void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3541 class DeferredNumberTagI: public LDeferredCode {
3542 public:
3543 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3544 : LDeferredCode(codegen), instr_(instr) { }
3545 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003546 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003547 private:
3548 LNumberTagI* instr_;
3549 };
3550
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003551 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003552 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3553 Register reg = ToRegister(input);
3554
3555 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3556 __ SmiTag(reg);
3557 __ j(overflow, deferred->entry());
3558 __ bind(deferred->exit());
3559}
3560
3561
3562void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3563 Label slow;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003564 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003565 Register tmp = reg.is(eax) ? ecx : eax;
3566
3567 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003568 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003569
3570 // There was overflow, so bits 30 and 31 of the original integer
3571 // disagree. Try to allocate a heap number in new space and store
3572 // the value in there. If that fails, call the runtime system.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003573 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003574 __ SmiUntag(reg);
3575 __ xor_(reg, 0x80000000);
3576 __ cvtsi2sd(xmm0, Operand(reg));
3577 if (FLAG_inline_new) {
3578 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003579 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003580 }
3581
3582 // Slow case: Call the runtime system to do the number allocation.
3583 __ bind(&slow);
3584
3585 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3586 // register is stored, as this register is in the pointer map, but contains an
3587 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003588 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003589 // NumberTagI and NumberTagD use the context from the frame, rather than
3590 // the environment's HContext or HInlinedContext value.
3591 // They only call Runtime::kAllocateHeapNumber.
3592 // The corresponding HChange instructions are added in a phase that does
3593 // not have easy access to the local context.
3594 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3595 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
3596 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003597 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003598 if (!reg.is(eax)) __ mov(reg, eax);
3599
3600 // Done. Put the value in xmm0 into the value of the allocated heap
3601 // number.
3602 __ bind(&done);
3603 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003604 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003605}
3606
3607
3608void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3609 class DeferredNumberTagD: public LDeferredCode {
3610 public:
3611 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3612 : LDeferredCode(codegen), instr_(instr) { }
3613 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003614 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003615 private:
3616 LNumberTagD* instr_;
3617 };
3618
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003619 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003620 Register reg = ToRegister(instr->result());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003621 Register tmp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622
3623 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3624 if (FLAG_inline_new) {
3625 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
3626 } else {
3627 __ jmp(deferred->entry());
3628 }
3629 __ bind(deferred->exit());
3630 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
3631}
3632
3633
3634void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3635 // TODO(3095996): Get rid of this. For now, we need to make the
3636 // result register contain a valid pointer because it is already
3637 // contained in the register pointer map.
3638 Register reg = ToRegister(instr->result());
3639 __ Set(reg, Immediate(0));
3640
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003641 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003642 // NumberTagI and NumberTagD use the context from the frame, rather than
3643 // the environment's HContext or HInlinedContext value.
3644 // They only call Runtime::kAllocateHeapNumber.
3645 // The corresponding HChange instructions are added in a phase that does
3646 // not have easy access to the local context.
3647 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3648 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003649 RecordSafepointWithRegisters(
3650 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003651 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003652}
3653
3654
3655void LCodeGen::DoSmiTag(LSmiTag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003656 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003657 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3658 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3659 __ SmiTag(ToRegister(input));
3660}
3661
3662
3663void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003664 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003665 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3666 if (instr->needs_check()) {
3667 __ test(ToRegister(input), Immediate(kSmiTagMask));
3668 DeoptimizeIf(not_zero, instr->environment());
3669 }
3670 __ SmiUntag(ToRegister(input));
3671}
3672
3673
3674void LCodeGen::EmitNumberUntagD(Register input_reg,
3675 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003676 bool deoptimize_on_undefined,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003677 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003678 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003679
3680 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003681 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003682
3683 // Heap number map check.
3684 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003686 if (deoptimize_on_undefined) {
3687 DeoptimizeIf(not_equal, env);
3688 } else {
3689 Label heap_number;
3690 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003691
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003692 __ cmp(input_reg, factory()->undefined_value());
3693 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003694
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003695 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003696 ExternalReference nan =
3697 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003698 __ movdbl(result_reg, Operand::StaticVariable(nan));
3699 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003700
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003701 __ bind(&heap_number);
3702 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003703 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003704 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003705 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706
3707 // Smi to XMM conversion
3708 __ bind(&load_smi);
3709 __ SmiUntag(input_reg); // Untag smi before converting to float.
3710 __ cvtsi2sd(result_reg, Operand(input_reg));
3711 __ SmiTag(input_reg); // Retag smi.
3712 __ bind(&done);
3713}
3714
3715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003716void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003717 Label done, heap_number;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003718 Register input_reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003719
3720 // Heap number map check.
3721 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003723
3724 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003725 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003726 // Check for undefined. Undefined is converted to zero for truncating
3727 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 __ cmp(input_reg, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003729 DeoptimizeIf(not_equal, instr->environment());
3730 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003731 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003732
3733 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003734 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003735 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003736 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003737 // Use more powerful conversion when sse3 is available.
3738 // Load x87 register with heap number.
3739 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
3740 // Get exponent alone and check for too-big exponent.
3741 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3742 __ and_(input_reg, HeapNumber::kExponentMask);
3743 const uint32_t kTooBigExponent =
3744 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3745 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003746 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003747 // Pop FPU stack before deoptimizing.
3748 __ ffree(0);
3749 __ fincstp();
3750 DeoptimizeIf(no_condition, instr->environment());
3751
3752 // Reserve space for 64 bit answer.
3753 __ bind(&convert);
3754 __ sub(Operand(esp), Immediate(kDoubleSize));
3755 // Do conversion, which cannot fail because we checked the exponent.
3756 __ fisttp_d(Operand(esp, 0));
3757 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
3758 __ add(Operand(esp), Immediate(kDoubleSize));
3759 } else {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003760 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003761 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3762 __ cvttsd2si(input_reg, Operand(xmm0));
3763 __ cmp(input_reg, 0x80000000u);
3764 __ j(not_equal, &done);
3765 // Check if the input was 0x8000000 (kMinInt).
3766 // If no, then we got an overflow and we deoptimize.
3767 ExternalReference min_int = ExternalReference::address_of_min_int();
3768 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
3769 __ ucomisd(xmm_temp, xmm0);
3770 DeoptimizeIf(not_equal, instr->environment());
3771 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3772 }
3773 } else {
3774 // Deoptimize if we don't have a heap number.
3775 DeoptimizeIf(not_equal, instr->environment());
3776
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003777 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003778 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
3779 __ cvttsd2si(input_reg, Operand(xmm0));
3780 __ cvtsi2sd(xmm_temp, Operand(input_reg));
3781 __ ucomisd(xmm0, xmm_temp);
3782 DeoptimizeIf(not_equal, instr->environment());
3783 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3784 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3785 __ test(input_reg, Operand(input_reg));
3786 __ j(not_zero, &done);
3787 __ movmskpd(input_reg, xmm0);
3788 __ and_(input_reg, 1);
3789 DeoptimizeIf(not_zero, instr->environment());
3790 }
3791 }
3792 __ bind(&done);
3793}
3794
3795
3796void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003797 class DeferredTaggedToI: public LDeferredCode {
3798 public:
3799 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3800 : LDeferredCode(codegen), instr_(instr) { }
3801 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3802 virtual LInstruction* instr() { return instr_; }
3803 private:
3804 LTaggedToI* instr_;
3805 };
3806
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003807 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003808 ASSERT(input->IsRegister());
3809 ASSERT(input->Equals(instr->result()));
3810
3811 Register input_reg = ToRegister(input);
3812
3813 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3814
3815 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003816 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003817
3818 // Smi to int32 conversion
3819 __ SmiUntag(input_reg); // Untag smi.
3820
3821 __ bind(deferred->exit());
3822}
3823
3824
3825void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003826 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003827 ASSERT(input->IsRegister());
3828 LOperand* result = instr->result();
3829 ASSERT(result->IsDoubleRegister());
3830
3831 Register input_reg = ToRegister(input);
3832 XMMRegister result_reg = ToDoubleRegister(result);
3833
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003834 EmitNumberUntagD(input_reg, result_reg,
3835 instr->hydrogen()->deoptimize_on_undefined(),
3836 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003837}
3838
3839
3840void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003841 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003842 ASSERT(input->IsDoubleRegister());
3843 LOperand* result = instr->result();
3844 ASSERT(result->IsRegister());
3845
3846 XMMRegister input_reg = ToDoubleRegister(input);
3847 Register result_reg = ToRegister(result);
3848
3849 if (instr->truncating()) {
3850 // Performs a truncating conversion of a floating point number as used by
3851 // the JS bitwise operations.
3852 __ cvttsd2si(result_reg, Operand(input_reg));
3853 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003854 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003855 // This will deoptimize if the exponent of the input in out of range.
3856 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003857 Label convert, done;
3858 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003859 __ sub(Operand(esp), Immediate(kDoubleSize));
3860 __ movdbl(Operand(esp, 0), input_reg);
3861 // Get exponent alone and check for too-big exponent.
3862 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
3863 __ and_(result_reg, HeapNumber::kExponentMask);
3864 const uint32_t kTooBigExponent =
3865 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
3866 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003867 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003868 __ add(Operand(esp), Immediate(kDoubleSize));
3869 DeoptimizeIf(no_condition, instr->environment());
3870 __ bind(&convert);
3871 // Do conversion, which cannot fail because we checked the exponent.
3872 __ fld_d(Operand(esp, 0));
3873 __ fisttp_d(Operand(esp, 0));
3874 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
3875 __ add(Operand(esp), Immediate(kDoubleSize));
3876 __ bind(&done);
3877 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003878 Label done;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003879 Register temp_reg = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003880 XMMRegister xmm_scratch = xmm0;
3881
3882 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
3883 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003884 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003885
3886 // Get high 32 bits of the input in result_reg and temp_reg.
3887 __ pshufd(xmm_scratch, input_reg, 1);
3888 __ movd(Operand(temp_reg), xmm_scratch);
3889 __ mov(result_reg, temp_reg);
3890
3891 // Prepare negation mask in temp_reg.
3892 __ sar(temp_reg, kBitsPerInt - 1);
3893
3894 // Extract the exponent from result_reg and subtract adjusted
3895 // bias from it. The adjustment is selected in a way such that
3896 // when the difference is zero, the answer is in the low 32 bits
3897 // of the input, otherwise a shift has to be performed.
3898 __ shr(result_reg, HeapNumber::kExponentShift);
3899 __ and_(result_reg,
3900 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
3901 __ sub(Operand(result_reg),
3902 Immediate(HeapNumber::kExponentBias +
3903 HeapNumber::kExponentBits +
3904 HeapNumber::kMantissaBits));
3905 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
3906 // special exponents.
3907 DeoptimizeIf(greater, instr->environment());
3908
3909 // Zero out the sign and the exponent in the input (by shifting
3910 // it to the left) and restore the implicit mantissa bit,
3911 // i.e. convert the input to unsigned int64 shifted left by
3912 // kExponentBits.
3913 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
3914 // Minus zero has the most significant bit set and the other
3915 // bits cleared.
3916 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
3917 __ psllq(input_reg, HeapNumber::kExponentBits);
3918 __ por(input_reg, xmm_scratch);
3919
3920 // Get the amount to shift the input right in xmm_scratch.
3921 __ neg(result_reg);
3922 __ movd(xmm_scratch, Operand(result_reg));
3923
3924 // Shift the input right and extract low 32 bits.
3925 __ psrlq(input_reg, xmm_scratch);
3926 __ movd(Operand(result_reg), input_reg);
3927
3928 // Use the prepared mask in temp_reg to negate the result if necessary.
3929 __ xor_(result_reg, Operand(temp_reg));
3930 __ sub(result_reg, Operand(temp_reg));
3931 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003932 }
3933 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003934 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003935 __ cvttsd2si(result_reg, Operand(input_reg));
3936 __ cvtsi2sd(xmm0, Operand(result_reg));
3937 __ ucomisd(xmm0, input_reg);
3938 DeoptimizeIf(not_equal, instr->environment());
3939 DeoptimizeIf(parity_even, instr->environment()); // NaN.
3940 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3941 // The integer converted back is equal to the original. We
3942 // only have to test if we got -0 as an input.
3943 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003944 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003945 __ movmskpd(result_reg, input_reg);
3946 // Bit 0 contains the sign of the double in input_reg.
3947 // If input was positive, we are ok and return 0, otherwise
3948 // deoptimize.
3949 __ and_(result_reg, 1);
3950 DeoptimizeIf(not_zero, instr->environment());
3951 }
3952 __ bind(&done);
3953 }
3954}
3955
3956
3957void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003958 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003959 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003960 DeoptimizeIf(not_zero, instr->environment());
3961}
3962
3963
3964void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
3965 LOperand* input = instr->InputAt(0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003966 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003967 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003968}
3969
3970
3971void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003972 Register input = ToRegister(instr->InputAt(0));
3973 Register temp = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003974
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003975 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003976
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003977 if (instr->hydrogen()->is_interval_check()) {
3978 InstanceType first;
3979 InstanceType last;
3980 instr->hydrogen()->GetCheckInterval(&first, &last);
3981
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003982 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3983 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003984
3985 // If there is only one type in the interval check for equality.
3986 if (first == last) {
3987 DeoptimizeIf(not_equal, instr->environment());
3988 } else {
3989 DeoptimizeIf(below, instr->environment());
3990 // Omit check for the last type.
3991 if (last != LAST_TYPE) {
3992 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
3993 static_cast<int8_t>(last));
3994 DeoptimizeIf(above, instr->environment());
3995 }
3996 }
3997 } else {
3998 uint8_t mask;
3999 uint8_t tag;
4000 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4001
4002 if (IsPowerOf2(mask)) {
4003 ASSERT(tag == 0 || IsPowerOf2(tag));
4004 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
4005 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4006 } else {
4007 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
4008 __ and_(temp, mask);
4009 __ cmpb(Operand(temp), tag);
4010 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004011 }
4012 }
4013}
4014
4015
4016void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004017 Handle<JSFunction> target = instr->hydrogen()->target();
4018 if (isolate()->heap()->InNewSpace(*target)) {
4019 Register reg = ToRegister(instr->value());
4020 Handle<JSGlobalPropertyCell> cell =
4021 isolate()->factory()->NewJSGlobalPropertyCell(target);
4022 __ cmp(reg, Operand::Cell(cell));
4023 } else {
4024 Operand operand = ToOperand(instr->value());
4025 __ cmp(operand, instr->hydrogen()->target());
4026 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004027 DeoptimizeIf(not_equal, instr->environment());
4028}
4029
4030
4031void LCodeGen::DoCheckMap(LCheckMap* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004032 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004033 ASSERT(input->IsRegister());
4034 Register reg = ToRegister(input);
4035 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
4036 instr->hydrogen()->map());
4037 DeoptimizeIf(not_equal, instr->environment());
4038}
4039
4040
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004041void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4042 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
4043 Register result_reg = ToRegister(instr->result());
4044 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
4045}
4046
4047
4048void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4049 ASSERT(instr->unclamped()->Equals(instr->result()));
4050 Register value_reg = ToRegister(instr->result());
4051 __ ClampUint8(value_reg);
4052}
4053
4054
4055void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4056 ASSERT(instr->unclamped()->Equals(instr->result()));
4057 Register input_reg = ToRegister(instr->unclamped());
4058 Label is_smi, done, heap_number;
4059
4060 __ JumpIfSmi(input_reg, &is_smi);
4061
4062 // Check for heap number
4063 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4064 factory()->heap_number_map());
4065 __ j(equal, &heap_number, Label::kNear);
4066
4067 // Check for undefined. Undefined is converted to zero for clamping
4068 // conversions.
4069 __ cmp(input_reg, factory()->undefined_value());
4070 DeoptimizeIf(not_equal, instr->environment());
4071 __ mov(input_reg, 0);
4072 __ jmp(&done, Label::kNear);
4073
4074 // Heap number
4075 __ bind(&heap_number);
4076 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4077 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
4078 __ jmp(&done, Label::kNear);
4079
4080 // smi
4081 __ bind(&is_smi);
4082 __ SmiUntag(input_reg);
4083 __ ClampUint8(input_reg);
4084
4085 __ bind(&done);
4086}
4087
4088
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004089void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004090 if (isolate()->heap()->InNewSpace(*object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004091 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 isolate()->factory()->NewJSGlobalPropertyCell(object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004093 __ mov(result, Operand::Cell(cell));
4094 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004095 __ mov(result, object);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004096 }
4097}
4098
4099
4100void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004101 Register reg = ToRegister(instr->TempAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004102
4103 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004104 Handle<JSObject> current_prototype = instr->prototype();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004105
4106 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004107 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004108
4109 // Check prototype maps up to the holder.
4110 while (!current_prototype.is_identical_to(holder)) {
4111 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
4112 Handle<Map>(current_prototype->map()));
4113 DeoptimizeIf(not_equal, instr->environment());
4114 current_prototype =
4115 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4116 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004117 LoadHeapObject(reg, current_prototype);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004118 }
4119
4120 // Check the holder map.
4121 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
4122 Handle<Map>(current_prototype->map()));
4123 DeoptimizeIf(not_equal, instr->environment());
4124}
4125
4126
4127void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004128 ASSERT(ToRegister(instr->context()).is(esi));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004129
4130 Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements();
4131 ASSERT_EQ(2, constant_elements->length());
4132 ElementsKind constant_elements_kind =
4133 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
4134
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004135 // Setup the parameters to the stub/runtime call.
4136 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4137 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
4138 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004139 __ push(Immediate(constant_elements));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004140
4141 // Pick the right runtime function or stub to call.
4142 int length = instr->hydrogen()->length();
4143 if (instr->hydrogen()->IsCopyOnWrite()) {
4144 ASSERT(instr->hydrogen()->depth() == 1);
4145 FastCloneShallowArrayStub::Mode mode =
4146 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4147 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004148 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004149 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004150 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004151 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004152 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004153 } else {
4154 FastCloneShallowArrayStub::Mode mode =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004155 constant_elements_kind == FAST_DOUBLE_ELEMENTS
4156 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
4157 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004158 FastCloneShallowArrayStub stub(mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004159 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004160 }
4161}
4162
4163
4164void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004165 ASSERT(ToRegister(instr->context()).is(esi));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004166 Handle<FixedArray> constant_properties =
4167 instr->hydrogen()->constant_properties();
4168
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004169 // Setup the parameters to the stub/runtime call.
4170 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4171 __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
4172 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004173 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 int flags = instr->hydrogen()->fast_elements()
4175 ? ObjectLiteral::kFastElements
4176 : ObjectLiteral::kNoFlags;
4177 flags |= instr->hydrogen()->has_function()
4178 ? ObjectLiteral::kHasFunction
4179 : ObjectLiteral::kNoFlags;
4180 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004181
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004182 // Pick the right runtime function or stub to call.
4183 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004184 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004185 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004186 } else if (flags != ObjectLiteral::kFastElements ||
4187 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004188 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00004189 } else {
4190 FastCloneShallowObjectStub stub(properties_count);
4191 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004192 }
4193}
4194
4195
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004196void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
4197 ASSERT(ToRegister(instr->InputAt(0)).is(eax));
4198 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004199 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004200}
4201
4202
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004203void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004204 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004205 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004206 // Registers will be used as follows:
4207 // edi = JS function.
4208 // ecx = literals array.
4209 // ebx = regexp literal.
4210 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004211 // esi = context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004212 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4213 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
4214 int literal_offset = FixedArray::kHeaderSize +
4215 instr->hydrogen()->literal_index() * kPointerSize;
4216 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004218 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004219
4220 // Create regexp literal using runtime function
4221 // Result will be in eax.
4222 __ push(ecx);
4223 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
4224 __ push(Immediate(instr->hydrogen()->pattern()));
4225 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004226 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004227 __ mov(ebx, eax);
4228
4229 __ bind(&materialized);
4230 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
4231 Label allocated, runtime_allocate;
4232 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
4233 __ jmp(&allocated);
4234
4235 __ bind(&runtime_allocate);
4236 __ push(ebx);
4237 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004238 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004239 __ pop(ebx);
4240
4241 __ bind(&allocated);
4242 // Copy the content into the newly allocated memory.
4243 // (Unroll copy loop once for better throughput).
4244 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4245 __ mov(edx, FieldOperand(ebx, i));
4246 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
4247 __ mov(FieldOperand(eax, i), edx);
4248 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
4249 }
4250 if ((size % (2 * kPointerSize)) != 0) {
4251 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
4252 __ mov(FieldOperand(eax, size - kPointerSize), edx);
4253 }
4254}
4255
4256
4257void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004258 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004259 // Use the fast case closure allocation code that allocates in new
4260 // space for nested functions that don't need literals cloning.
4261 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004262 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 if (!pretenure && shared_info->num_literals() == 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004264 FastNewClosureStub stub(shared_info->strict_mode_flag());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004265 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004266 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004267 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004268 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004269 __ push(Immediate(shared_info));
4270 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004271 ? factory()->true_value()
4272 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004273 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004274 }
4275}
4276
4277
4278void LCodeGen::DoTypeof(LTypeof* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004279 LOperand* input = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004280 if (input->IsConstantOperand()) {
4281 __ push(ToImmediate(input));
4282 } else {
4283 __ push(ToOperand(input));
4284 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004285 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004286}
4287
4288
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004289void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00004290 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004291 int true_block = chunk_->LookupDestination(instr->true_block_id());
4292 int false_block = chunk_->LookupDestination(instr->false_block_id());
4293 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4294 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4295
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004296 Condition final_branch_condition =
4297 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
4298 if (final_branch_condition != no_condition) {
4299 EmitBranch(true_block, false_block, final_branch_condition);
4300 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004301}
4302
4303
4304Condition LCodeGen::EmitTypeofIs(Label* true_label,
4305 Label* false_label,
4306 Register input,
4307 Handle<String> type_name) {
4308 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004309 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004310 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004311 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004313 final_branch_condition = equal;
4314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004315 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004316 __ JumpIfSmi(input, false_label);
4317 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
4318 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004319 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4320 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004321 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004323 } else if (type_name->Equals(heap()->boolean_symbol())) {
4324 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004325 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004327 final_branch_condition = equal;
4328
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004329 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
4330 __ cmp(input, factory()->null_value());
4331 final_branch_condition = equal;
4332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004333 } else if (type_name->Equals(heap()->undefined_symbol())) {
4334 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004335 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004336 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004337 // Check for undetectable objects => true.
4338 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
4339 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4340 1 << Map::kIsUndetectable);
4341 final_branch_condition = not_zero;
4342
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004344 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004345 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004346 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
4347 __ j(equal, true_label);
4348 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
4349 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004351 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004352 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004353 if (!FLAG_harmony_typeof) {
4354 __ cmp(input, factory()->null_value());
4355 __ j(equal, true_label);
4356 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004357 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004358 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004359 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4360 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004361 // Check for undetectable objects => false.
4362 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
4363 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004364 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004365
4366 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004367 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004368 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004369 return final_branch_condition;
4370}
4371
4372
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004373void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4374 Register temp = ToRegister(instr->TempAt(0));
4375 int true_block = chunk_->LookupDestination(instr->true_block_id());
4376 int false_block = chunk_->LookupDestination(instr->false_block_id());
4377
4378 EmitIsConstructCall(temp);
4379 EmitBranch(true_block, false_block, equal);
4380}
4381
4382
4383void LCodeGen::EmitIsConstructCall(Register temp) {
4384 // Get the frame pointer for the calling frame.
4385 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
4386
4387 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004388 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004389 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
4390 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004391 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004392 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
4393
4394 // Check the marker in the calling frame.
4395 __ bind(&check_frame_marker);
4396 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
4397 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
4398}
4399
4400
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004401void LCodeGen::EnsureSpaceForLazyDeopt() {
4402 // Ensure that we have enough space after the previous lazy-bailout
4403 // instruction for patching the code here.
4404 int current_pc = masm()->pc_offset();
4405 int patch_size = Deoptimizer::patch_size();
4406 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
4407 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
4408 while (padding_size-- > 0) {
4409 __ nop();
4410 }
4411 }
4412 last_lazy_deopt_pc_ = current_pc;
4413}
4414
4415
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004416void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004417 EnsureSpaceForLazyDeopt();
4418 ASSERT(instr->HasEnvironment());
4419 LEnvironment* env = instr->environment();
4420 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4421 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004422}
4423
4424
4425void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
4426 DeoptimizeIf(no_condition, instr->environment());
4427}
4428
4429
4430void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
4431 LOperand* obj = instr->object();
4432 LOperand* key = instr->key();
4433 __ push(ToOperand(obj));
4434 if (key->IsConstantOperand()) {
4435 __ push(ToImmediate(key));
4436 } else {
4437 __ push(ToOperand(key));
4438 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004439 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4440 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004441 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004442 // Create safepoint generator that will also ensure enough space in the
4443 // reloc info for patching in deoptimization (since this is invoking a
4444 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004445 SafepointGenerator safepoint_generator(
4446 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004447 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004448 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004449}
4450
4451
ager@chromium.org04921a82011-06-27 13:21:41 +00004452void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004453 PushSafepointRegistersScope scope(this);
4454 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4455 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
4456 RecordSafepointWithLazyDeopt(
4457 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
4458 ASSERT(instr->HasEnvironment());
4459 LEnvironment* env = instr->environment();
4460 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004461}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004462
ager@chromium.org04921a82011-06-27 13:21:41 +00004463
4464void LCodeGen::DoStackCheck(LStackCheck* instr) {
4465 class DeferredStackCheck: public LDeferredCode {
4466 public:
4467 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
4468 : LDeferredCode(codegen), instr_(instr) { }
4469 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004470 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00004471 private:
4472 LStackCheck* instr_;
4473 };
4474
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004475 ASSERT(instr->HasEnvironment());
4476 LEnvironment* env = instr->environment();
4477 // There is no LLazyBailout instruction for stack-checks. We have to
4478 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00004479 if (instr->hydrogen()->is_function_entry()) {
4480 // Perform stack overflow check.
4481 Label done;
4482 ExternalReference stack_limit =
4483 ExternalReference::address_of_stack_limit(isolate());
4484 __ cmp(esp, Operand::StaticVariable(stack_limit));
4485 __ j(above_equal, &done, Label::kNear);
4486
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004487 ASSERT(instr->context()->IsRegister());
4488 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00004489 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004490 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004491 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00004492 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004493 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4494 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00004495 } else {
4496 ASSERT(instr->hydrogen()->is_backwards_branch());
4497 // Perform stack overflow check if this goto needs it before jumping.
4498 DeferredStackCheck* deferred_stack_check =
4499 new DeferredStackCheck(this, instr);
4500 ExternalReference stack_limit =
4501 ExternalReference::address_of_stack_limit(isolate());
4502 __ cmp(esp, Operand::StaticVariable(stack_limit));
4503 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004504 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00004505 __ bind(instr->done_label());
4506 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004507 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
4508 // Don't record a deoptimization index for the safepoint here.
4509 // This will be done explicitly when emitting call and the safepoint in
4510 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00004511 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004512}
4513
4514
4515void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
4516 // This is a pseudo-instruction that ensures that the environment here is
4517 // properly registered for deoptimization and records the assembler's PC
4518 // offset.
4519 LEnvironment* environment = instr->environment();
4520 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4521 instr->SpilledDoubleRegisterArray());
4522
4523 // If the environment were already registered, we would have no way of
4524 // backpatching it with the spill slot operands.
4525 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004526 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004527 ASSERT(osr_pc_offset_ == -1);
4528 osr_pc_offset_ = masm()->pc_offset();
4529}
4530
4531
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004532void LCodeGen::DoIn(LIn* instr) {
4533 LOperand* obj = instr->object();
4534 LOperand* key = instr->key();
4535 if (key->IsConstantOperand()) {
4536 __ push(ToImmediate(key));
4537 } else {
4538 __ push(ToOperand(key));
4539 }
4540 if (obj->IsConstantOperand()) {
4541 __ push(ToImmediate(obj));
4542 } else {
4543 __ push(ToOperand(obj));
4544 }
4545 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4546 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004547 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004548 SafepointGenerator safepoint_generator(
4549 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004550 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004551}
4552
4553
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004554#undef __
4555
4556} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004557
4558#endif // V8_TARGET_ARCH_IA32