blob: d344e3361792870169a47c2098ad999d2d96068e [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000028#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_IA32)
31
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "ia32/lithium-codegen-ia32.h"
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000033#include "ic.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "code-stubs.h"
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000035#include "deoptimizer.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "stub-cache.h"
erikcorry0ad885c2011-11-21 13:51:57 +000037#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038
39namespace v8 {
40namespace internal {
41
42
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000043// When invoking builtins, we need to record the safepoint in the middle of
44// the invoke instruction sequence generated by the macro assembler.
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000045class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046 public:
47 SafepointGenerator(LCodeGen* codegen,
48 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000049 Safepoint::DeoptMode mode)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050 : codegen_(codegen),
51 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000052 deopt_mode_(mode) {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053 virtual ~SafepointGenerator() { }
54
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055 virtual void BeforeCall(int call_size) const {}
56
57 virtual void AfterCall() const {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000058 codegen_->RecordSafepoint(pointers_, deopt_mode_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000059 }
60
61 private:
62 LCodeGen* codegen_;
63 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000064 Safepoint::DeoptMode deopt_mode_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065};
66
67
68#define __ masm()->
69
70bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000071 HPhase phase("Z_Code generation", chunk());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000072 ASSERT(is_unused());
73 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000075 // Open a frame scope to indicate that there is a frame on the stack. The
76 // MANUAL indicates that the scope shouldn't actually generate code to set up
77 // the frame (that is done in GeneratePrologue).
78 FrameScope frame_scope(masm_, StackFrame::MANUAL);
79
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000080 dynamic_frame_alignment_ = info()->IsOptimizing() &&
81 ((chunk()->num_double_slots() > 2 &&
82 !chunk()->graph()->is_recursive()) ||
83 !info()->osr_ast_id().IsNone());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000084
kasperl@chromium.orga5551262010-12-07 12:49:48 +000085 return GeneratePrologue() &&
86 GenerateBody() &&
87 GenerateDeferredCode() &&
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000088 GenerateJumpTable() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000089 GenerateSafepointTable();
90}
91
92
93void LCodeGen::FinishCode(Handle<Code> code) {
94 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000095 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000096 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 PopulateDeoptimizationData(code);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000098 if (!info()->IsStub()) {
99 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
100 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000101}
102
103
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000104void LCodeGen::Abort(const char* reason) {
105 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000106 status_ = ABORTED;
107}
108
109
110void LCodeGen::Comment(const char* format, ...) {
111 if (!FLAG_code_comments) return;
112 char buffer[4 * KB];
113 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
114 va_list arguments;
115 va_start(arguments, format);
116 builder.AddFormattedList(format, arguments);
117 va_end(arguments);
118
119 // Copy the string before recording it in the assembler to avoid
120 // issues when the stack allocated buffer goes out of scope.
121 size_t length = builder.position();
122 Vector<char> copy = Vector<char>::New(length + 1);
123 memcpy(copy.start(), builder.Finalize(), copy.length());
124 masm()->RecordComment(copy.start());
125}
126
127
128bool LCodeGen::GeneratePrologue() {
129 ASSERT(is_generating());
130
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000131 if (info()->IsOptimizing()) {
132 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000133
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000134#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000135 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000136 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000137 __ int3();
138 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000139#endif
140
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000141 // Strict mode functions and builtins need to replace the receiver
142 // with undefined when called as functions (without an explicit
143 // receiver object). ecx is zero for method calls and non-zero for
144 // function calls.
145 if (!info_->is_classic_mode() || info_->is_native()) {
146 Label ok;
147 __ test(ecx, Operand(ecx));
148 __ j(zero, &ok, Label::kNear);
149 // +1 for return address.
150 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
151 __ mov(Operand(esp, receiver_offset),
152 Immediate(isolate()->factory()->undefined_value()));
153 __ bind(&ok);
154 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000155
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000156 if (dynamic_frame_alignment_) {
157 // Move state of dynamic frame alignment into edx.
158 __ mov(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000159
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000160 Label do_not_pad, align_loop;
161 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
162 // Align esp + 4 to a multiple of 2 * kPointerSize.
163 __ test(esp, Immediate(kPointerSize));
164 __ j(not_zero, &do_not_pad, Label::kNear);
165 __ push(Immediate(0));
166 __ mov(ebx, esp);
167 __ mov(edx, Immediate(kAlignmentPaddingPushed));
168 // Copy arguments, receiver, and return address.
169 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000170
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000171 __ bind(&align_loop);
172 __ mov(eax, Operand(ebx, 1 * kPointerSize));
173 __ mov(Operand(ebx, 0), eax);
174 __ add(Operand(ebx), Immediate(kPointerSize));
175 __ dec(ecx);
176 __ j(not_zero, &align_loop, Label::kNear);
177 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
178 __ bind(&do_not_pad);
179 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000180 }
181
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000182 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000183 if (NeedsEagerFrame()) {
184 ASSERT(!frame_is_built_);
185 frame_is_built_ = true;
186 __ push(ebp); // Caller's frame pointer.
187 __ mov(ebp, esp);
188 __ push(esi); // Callee's context.
189 if (info()->IsStub()) {
190 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
191 } else {
192 __ push(edi); // Callee's JS function.
193 }
194 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000195
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000196 if (info()->IsOptimizing() &&
197 dynamic_frame_alignment_ &&
198 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000199 __ test(esp, Immediate(kPointerSize));
200 __ Assert(zero, "frame is expected to be aligned");
201 }
202
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000203 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000204 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000205 ASSERT(slots != 0 || !info()->IsOptimizing());
206 if (slots > 0) {
207 if (slots == 1) {
208 if (dynamic_frame_alignment_) {
209 __ push(edx);
210 } else {
211 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000212 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000213 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000214 if (FLAG_debug_code) {
215 __ mov(Operand(eax), Immediate(slots));
216 Label loop;
217 __ bind(&loop);
218 __ push(Immediate(kSlotsZapValue));
219 __ dec(eax);
220 __ j(not_zero, &loop);
221 } else {
222 __ sub(Operand(esp), Immediate(slots * kPointerSize));
223#ifdef _MSC_VER
224 // On windows, you may not access the stack more than one page below
225 // the most recently mapped page. To make the allocated area randomly
226 // accessible, we write to each page in turn (the value is irrelevant).
227 const int kPageSize = 4 * KB;
228 for (int offset = slots * kPointerSize - kPageSize;
229 offset > 0;
230 offset -= kPageSize) {
231 __ mov(Operand(esp, offset), eax);
232 }
233#endif
234 }
235
236 // Store dynamic frame alignment state in the first local.
237 if (dynamic_frame_alignment_) {
238 __ mov(Operand(ebp,
239 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
240 edx);
241 } else {
242 __ mov(Operand(ebp,
243 JavaScriptFrameConstants::kDynamicAlignmentStateOffset),
244 Immediate(kNoAlignmentPadding));
245 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000246 }
247 }
248
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000249 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000250 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000251 if (heap_slots > 0) {
252 Comment(";;; Allocate local context");
253 // Argument to NewContext is the function, which is still in edi.
254 __ push(edi);
255 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
256 FastNewContextStub stub(heap_slots);
257 __ CallStub(&stub);
258 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000259 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000260 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000261 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000262 // Context is returned in both eax and esi. It replaces the context
263 // passed to us. It's saved in the stack and kept live in esi.
264 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
265
266 // Copy parameters into context if necessary.
267 int num_parameters = scope()->num_parameters();
268 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000269 Variable* var = scope()->parameter(i);
270 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000271 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
272 (num_parameters - 1 - i) * kPointerSize;
273 // Load parameter from stack.
274 __ mov(eax, Operand(ebp, parameter_offset));
275 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000276 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000277 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000278 // Update the write barrier. This clobbers eax and ebx.
279 __ RecordWriteContextSlot(esi,
280 context_offset,
281 eax,
282 ebx,
283 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000284 }
285 }
286 Comment(";;; End allocate local context");
287 }
288
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000290 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000291 // We have not executed any compiled code yet, so esi still holds the
292 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000293 __ CallRuntime(Runtime::kTraceEnter, 0);
294 }
295 return !is_aborted();
296}
297
298
299bool LCodeGen::GenerateBody() {
300 ASSERT(is_generating());
301 bool emit_instructions = true;
302 for (current_instruction_ = 0;
303 !is_aborted() && current_instruction_ < instructions_->length();
304 current_instruction_++) {
305 LInstruction* instr = instructions_->at(current_instruction_);
306 if (instr->IsLabel()) {
307 LLabel* label = LLabel::cast(instr);
308 emit_instructions = !label->HasReplacement();
309 }
310
311 if (emit_instructions) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000312 if (FLAG_code_comments) {
313 HValue* hydrogen = instr->hydrogen_value();
314 if (hydrogen != NULL) {
315 if (hydrogen->IsChange()) {
316 HValue* changed_value = HChange::cast(hydrogen)->value();
317 int use_id = 0;
318 const char* use_mnemo = "dead";
319 if (hydrogen->UseCount() >= 1) {
320 HValue* use_value = hydrogen->uses().value();
321 use_id = use_value->id();
322 use_mnemo = use_value->Mnemonic();
323 }
324 Comment(";;; @%d: %s. <of #%d %s for #%d %s>",
325 current_instruction_, instr->Mnemonic(),
326 changed_value->id(), changed_value->Mnemonic(),
327 use_id, use_mnemo);
328 } else {
329 Comment(";;; @%d: %s. <#%d>", current_instruction_,
330 instr->Mnemonic(), hydrogen->id());
331 }
332 } else {
333 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
334 }
335 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000336 instr->CompileToNative(this);
337 }
338 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000339 EnsureSpaceForLazyDeopt();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000340 return !is_aborted();
341}
342
343
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000344bool LCodeGen::GenerateJumpTable() {
345 Label needs_frame_not_call;
346 Label needs_frame_is_call;
347 for (int i = 0; i < jump_table_.length(); i++) {
348 __ bind(&jump_table_[i].label);
349 Address entry = jump_table_[i].address;
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000350 bool is_lazy_deopt = jump_table_[i].is_lazy_deopt;
351 Deoptimizer::BailoutType type =
352 is_lazy_deopt ? Deoptimizer::LAZY : Deoptimizer::EAGER;
353 int id = Deoptimizer::GetDeoptimizationId(entry, type);
354 if (id == Deoptimizer::kNotDeoptimizationEntry) {
355 Comment(";;; jump table entry %d.", i);
356 } else {
357 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
358 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000359 if (jump_table_[i].needs_frame) {
360 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000361 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000362 if (needs_frame_is_call.is_bound()) {
363 __ jmp(&needs_frame_is_call);
364 } else {
365 __ bind(&needs_frame_is_call);
366 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
367 // This variant of deopt can only be used with stubs. Since we don't
368 // have a function pointer to install in the stack frame that we're
369 // building, install a special marker there instead.
370 ASSERT(info()->IsStub());
371 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
372 // Push a PC inside the function so that the deopt code can find where
373 // the deopt comes from. It doesn't have to be the precise return
374 // address of a "calling" LAZY deopt, it only has to be somewhere
375 // inside the code body.
376 Label push_approx_pc;
377 __ call(&push_approx_pc);
378 __ bind(&push_approx_pc);
379 // Push the continuation which was stashed were the ebp should
380 // be. Replace it with the saved ebp.
381 __ push(MemOperand(esp, 3 * kPointerSize));
382 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
383 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
384 __ ret(0); // Call the continuation without clobbering registers.
385 }
386 } else {
387 if (needs_frame_not_call.is_bound()) {
388 __ jmp(&needs_frame_not_call);
389 } else {
390 __ bind(&needs_frame_not_call);
391 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
392 // This variant of deopt can only be used with stubs. Since we don't
393 // have a function pointer to install in the stack frame that we're
394 // building, install a special marker there instead.
395 ASSERT(info()->IsStub());
396 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
397 // Push the continuation which was stashed were the ebp should
398 // be. Replace it with the saved ebp.
399 __ push(MemOperand(esp, 2 * kPointerSize));
400 __ mov(MemOperand(esp, 3 * kPointerSize), ebp);
401 __ lea(ebp, MemOperand(esp, 3 * kPointerSize));
402 __ ret(0); // Call the continuation without clobbering registers.
403 }
404 }
405 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000406 if (is_lazy_deopt) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000407 __ call(entry, RelocInfo::RUNTIME_ENTRY);
408 } else {
409 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
410 }
411 }
412 }
413 return !is_aborted();
414}
415
416
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000417bool LCodeGen::GenerateDeferredCode() {
418 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000419 if (deferred_.length() > 0) {
420 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
421 LDeferredCode* code = deferred_[i];
422 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000423 if (NeedsDeferredFrame()) {
424 Comment(";;; Deferred build frame",
425 code->instruction_index(),
426 code->instr()->Mnemonic());
427 ASSERT(!frame_is_built_);
428 ASSERT(info()->IsStub());
429 frame_is_built_ = true;
430 // Build the frame in such a way that esi isn't trashed.
431 __ push(ebp); // Caller's frame pointer.
432 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
433 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
434 __ lea(ebp, Operand(esp, 2 * kPointerSize));
435 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000436 Comment(";;; Deferred code @%d: %s.",
437 code->instruction_index(),
438 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000439 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000440 if (NeedsDeferredFrame()) {
441 Comment(";;; Deferred destroy frame",
442 code->instruction_index(),
443 code->instr()->Mnemonic());
444 ASSERT(frame_is_built_);
445 frame_is_built_ = false;
446 __ mov(esp, ebp);
447 __ pop(ebp);
448 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000449 __ jmp(code->exit());
450 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000451 }
452
453 // Deferred code is the last part of the instruction sequence. Mark
454 // the generated code as done unless we bailed out.
455 if (!is_aborted()) status_ = DONE;
456 return !is_aborted();
457}
458
459
460bool LCodeGen::GenerateSafepointTable() {
461 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000462 if (!info()->IsStub()) {
463 // For lazy deoptimization we need space to patch a call after every call.
464 // Ensure there is always space for such patching, even if the code ends
465 // in a call.
466 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
467 while (masm()->pc_offset() < target_offset) {
468 masm()->nop();
469 }
470 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000471 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000472 return !is_aborted();
473}
474
475
476Register LCodeGen::ToRegister(int index) const {
477 return Register::FromAllocationIndex(index);
478}
479
480
481XMMRegister LCodeGen::ToDoubleRegister(int index) const {
482 return XMMRegister::FromAllocationIndex(index);
483}
484
485
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000486bool LCodeGen::IsX87TopOfStack(LOperand* op) const {
487 return op->IsDoubleRegister();
488}
489
490
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000491Register LCodeGen::ToRegister(LOperand* op) const {
492 ASSERT(op->IsRegister());
493 return ToRegister(op->index());
494}
495
496
497XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
498 ASSERT(op->IsDoubleRegister());
499 return ToDoubleRegister(op->index());
500}
501
502
503int LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000504 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000505 return constant->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000506}
507
508
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000509Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000510 HConstant* constant = chunk_->LookupConstant(op);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000511 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000512 return constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000513}
514
515
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000516double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000517 HConstant* constant = chunk_->LookupConstant(op);
518 ASSERT(constant->HasDoubleValue());
519 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000520}
521
522
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000523bool LCodeGen::IsInteger32(LConstantOperand* op) const {
524 return chunk_->LookupLiteralRepresentation(op).IsInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000525}
526
527
528Operand LCodeGen::ToOperand(LOperand* op) const {
529 if (op->IsRegister()) return Operand(ToRegister(op));
530 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
531 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
532 int index = op->index();
533 if (index >= 0) {
534 // Local or spill slot. Skip the frame pointer, function, and
535 // context in the fixed part of the frame.
536 return Operand(ebp, -(index + 3) * kPointerSize);
537 } else {
538 // Incoming parameter. Skip the return address.
539 return Operand(ebp, -(index - 1) * kPointerSize);
540 }
541}
542
543
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000544Operand LCodeGen::HighOperand(LOperand* op) {
545 ASSERT(op->IsDoubleStackSlot());
546 int index = op->index();
547 int offset = (index >= 0) ? index + 3 : index - 1;
548 return Operand(ebp, -offset * kPointerSize);
549}
550
551
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000552void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000553 Translation* translation,
554 int* arguments_index,
555 int* arguments_count) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000556 if (environment == NULL) return;
557
558 // The translation includes one command per value in the environment.
559 int translation_size = environment->values()->length();
560 // The output frame height does not include the parameters.
561 int height = translation_size - environment->parameter_count();
562
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000563 // Function parameters are arguments to the outermost environment. The
564 // arguments index points to the first element of a sequence of tagged
565 // values on the stack that represent the arguments. This needs to be
566 // kept in sync with the LArgumentsElements implementation.
567 *arguments_index = -environment->parameter_count();
568 *arguments_count = environment->parameter_count();
569
570 WriteTranslation(environment->outer(),
571 translation,
572 arguments_index,
573 arguments_count);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000574 bool has_closure_id = !info()->closure().is_null() &&
575 *info()->closure() != *environment->closure();
576 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000577 ? DefineDeoptimizationLiteral(environment->closure())
578 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000579 switch (environment->frame_type()) {
580 case JS_FUNCTION:
581 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
582 break;
583 case JS_CONSTRUCT:
584 translation->BeginConstructStubFrame(closure_id, translation_size);
585 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000586 case JS_GETTER:
587 ASSERT(translation_size == 1);
588 ASSERT(height == 0);
589 translation->BeginGetterStubFrame(closure_id);
590 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000591 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000592 ASSERT(translation_size == 2);
593 ASSERT(height == 0);
594 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000595 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000596 case ARGUMENTS_ADAPTOR:
597 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
598 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000599 case STUB:
600 translation->BeginCompiledStubFrame();
601 break;
602 default:
603 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000604 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000605
606 // Inlined frames which push their arguments cause the index to be
607 // bumped and another stack area to be used for materialization.
608 if (environment->entry() != NULL &&
609 environment->entry()->arguments_pushed()) {
610 *arguments_index = *arguments_index < 0
611 ? GetStackSlotCount()
612 : *arguments_index + *arguments_count;
613 *arguments_count = environment->entry()->arguments_count() + 1;
614 }
615
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000616 for (int i = 0; i < translation_size; ++i) {
617 LOperand* value = environment->values()->at(i);
618 // spilled_registers_ and spilled_double_registers_ are either
619 // both NULL or both set.
620 if (environment->spilled_registers() != NULL && value != NULL) {
621 if (value->IsRegister() &&
622 environment->spilled_registers()[value->index()] != NULL) {
623 translation->MarkDuplicate();
624 AddToTranslation(translation,
625 environment->spilled_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000626 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000627 environment->HasUint32ValueAt(i),
628 *arguments_index,
629 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000630 } else if (
631 value->IsDoubleRegister() &&
632 environment->spilled_double_registers()[value->index()] != NULL) {
633 translation->MarkDuplicate();
634 AddToTranslation(
635 translation,
636 environment->spilled_double_registers()[value->index()],
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000637 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000638 false,
639 *arguments_index,
640 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000641 }
642 }
643
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000644 AddToTranslation(translation,
645 value,
646 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000647 environment->HasUint32ValueAt(i),
648 *arguments_index,
649 *arguments_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000650 }
651}
652
653
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000654void LCodeGen::AddToTranslation(Translation* translation,
655 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000656 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000657 bool is_uint32,
658 int arguments_index,
659 int arguments_count) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000660 if (op == NULL) {
661 // TODO(twuerthinger): Introduce marker operands to indicate that this value
662 // is not present and must be reconstructed from the deoptimizer. Currently
663 // this is only used for the arguments object.
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000664 translation->StoreArgumentsObject(arguments_index, arguments_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000665 } else if (op->IsStackSlot()) {
666 if (is_tagged) {
667 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000668 } else if (is_uint32) {
669 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670 } else {
671 translation->StoreInt32StackSlot(op->index());
672 }
673 } else if (op->IsDoubleStackSlot()) {
674 translation->StoreDoubleStackSlot(op->index());
675 } else if (op->IsArgument()) {
676 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000677 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000678 translation->StoreStackSlot(src_index);
679 } else if (op->IsRegister()) {
680 Register reg = ToRegister(op);
681 if (is_tagged) {
682 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000683 } else if (is_uint32) {
684 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 } else {
686 translation->StoreInt32Register(reg);
687 }
688 } else if (op->IsDoubleRegister()) {
689 XMMRegister reg = ToDoubleRegister(op);
690 translation->StoreDoubleRegister(reg);
691 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000692 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
693 int src_index = DefineDeoptimizationLiteral(constant->handle());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000694 translation->StoreLiteral(src_index);
695 } else {
696 UNREACHABLE();
697 }
698}
699
700
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000701void LCodeGen::CallCodeGeneric(Handle<Code> code,
702 RelocInfo::Mode mode,
703 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000704 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000705 ASSERT(instr != NULL);
706 LPointerMap* pointers = instr->pointer_map();
707 RecordPosition(pointers->position());
708 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000709 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000710
711 // Signal that we don't inline smi code before these stubs in the
712 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000713 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000714 code->kind() == Code::COMPARE_IC) {
715 __ nop();
716 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000717}
718
719
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000720void LCodeGen::CallCode(Handle<Code> code,
721 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000722 LInstruction* instr) {
723 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000724}
725
726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000727void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000728 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000729 LInstruction* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000730 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000731 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000732 LPointerMap* pointers = instr->pointer_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000733 RecordPosition(pointers->position());
734
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000735 __ CallRuntime(fun, argc);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000736
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000737 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000738
739 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000740}
741
742
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000743void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
744 int argc,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000745 LInstruction* instr,
746 LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000747 if (context->IsRegister()) {
748 if (!ToRegister(context).is(esi)) {
749 __ mov(esi, ToRegister(context));
750 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000752 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000753 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000754 HConstant* constant =
755 chunk_->LookupConstant(LConstantOperand::cast(context));
756 __ LoadHeapObject(esi, Handle<Context>::cast(constant->handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000757 } else {
758 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000759 }
760
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000761 __ CallRuntimeSaveDoubles(id);
762 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000763 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000764
765 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000766}
767
768
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000769void LCodeGen::RegisterEnvironmentForDeoptimization(
770 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000771 if (!environment->HasBeenRegistered()) {
772 // Physical stack frame layout:
773 // -x ............. -4 0 ..................................... y
774 // [incoming arguments] [spill slots] [pushed outgoing arguments]
775
776 // Layout of the environment:
777 // 0 ..................................................... size-1
778 // [parameters] [locals] [expression stack including arguments]
779
780 // Layout of the translation:
781 // 0 ........................................................ size - 1 + 4
782 // [expression stack including arguments] [locals] [4 words] [parameters]
783 // |>------------ translation_size ------------<|
784
785 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000786 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000787 int args_index = 0;
788 int args_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
790 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000791 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000792 ++jsframe_count;
793 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000794 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000795 Translation translation(&translations_, frame_count, jsframe_count, zone());
796 WriteTranslation(environment, &translation, &args_index, &args_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000797 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000798 int pc_offset = masm()->pc_offset();
799 environment->Register(deoptimization_index,
800 translation.index(),
801 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000802 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000803 }
804}
805
806
807void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000808 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000809 ASSERT(environment->HasBeenRegistered());
810 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000811 ASSERT(info()->IsOptimizing() || info()->IsStub());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000812 Deoptimizer::BailoutType bailout_type = info()->IsStub()
813 ? Deoptimizer::LAZY
814 : Deoptimizer::EAGER;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000815 Address entry = Deoptimizer::GetDeoptimizationEntry(id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000816 if (entry == NULL) {
817 Abort("bailout was not prepared");
818 return;
819 }
820
821 if (FLAG_deopt_every_n_times != 0) {
822 Handle<SharedFunctionInfo> shared(info_->shared_info());
823 Label no_deopt;
824 __ pushfd();
825 __ push(eax);
826 __ push(ebx);
827 __ mov(ebx, shared);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000828 __ mov(eax,
829 FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000830 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000831 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000832 if (FLAG_trap_on_deopt) __ int3();
833 __ mov(eax, Immediate(Smi::FromInt(FLAG_deopt_every_n_times)));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000834 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
835 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000836 __ pop(ebx);
837 __ pop(eax);
838 __ popfd();
839 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
840
841 __ bind(&no_deopt);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000842 __ mov(FieldOperand(ebx, SharedFunctionInfo::kStressDeoptCounterOffset),
843 eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000844 __ pop(ebx);
845 __ pop(eax);
846 __ popfd();
847 }
848
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000849 ASSERT(info()->IsStub() || frame_is_built_);
850 bool lazy_deopt_needed = info()->IsStub();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000851 if (cc == no_condition) {
852 if (FLAG_trap_on_deopt) __ int3();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000853 if (lazy_deopt_needed) {
854 __ call(entry, RelocInfo::RUNTIME_ENTRY);
855 } else {
856 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
857 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000858 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000859 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000860 if (FLAG_trap_on_deopt) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000861 __ j(NegateCondition(cc), &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000862 __ int3();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000863 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000864 if (!lazy_deopt_needed && frame_is_built_) {
865 if (FLAG_trap_on_deopt) {
866 __ jmp(entry, RelocInfo::RUNTIME_ENTRY);
867 } else {
868 __ j(cc, entry, RelocInfo::RUNTIME_ENTRY);
869 }
870 } else {
871 // We often have several deopts to the same entry, reuse the last
872 // jump entry if this is the case.
873 if (jump_table_.is_empty() ||
874 jump_table_.last().address != entry ||
875 jump_table_.last().needs_frame != !frame_is_built_ ||
876 jump_table_.last().is_lazy_deopt != lazy_deopt_needed) {
877 JumpTableEntry table_entry(entry, !frame_is_built_, lazy_deopt_needed);
878 jump_table_.Add(table_entry, zone());
879 }
880 if (FLAG_trap_on_deopt) {
881 __ jmp(&jump_table_.last().label);
882 } else {
883 __ j(cc, &jump_table_.last().label);
884 }
885 }
886 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000887 }
888}
889
890
891void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
892 int length = deoptimizations_.length();
893 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000894 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000896
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000897 Handle<ByteArray> translations = translations_.CreateByteArray();
898 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000899 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
900
901 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000903 for (int i = 0; i < deoptimization_literals_.length(); i++) {
904 literals->set(i, *deoptimization_literals_[i]);
905 }
906 data->SetLiteralArray(*literals);
907
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000908 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000909 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
910
911 // Populate the deoptimization entries.
912 for (int i = 0; i < length; i++) {
913 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000914 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000915 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
916 data->SetArgumentsStackHeight(i,
917 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000918 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000919 }
920 code->set_deoptimization_data(*data);
921}
922
923
924int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
925 int result = deoptimization_literals_.length();
926 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
927 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
928 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000929 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000930 return result;
931}
932
933
934void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
935 ASSERT(deoptimization_literals_.length() == 0);
936
937 const ZoneList<Handle<JSFunction> >* inlined_closures =
938 chunk()->inlined_closures();
939
940 for (int i = 0, length = inlined_closures->length();
941 i < length;
942 i++) {
943 DefineDeoptimizationLiteral(inlined_closures->at(i));
944 }
945
946 inlined_function_count_ = deoptimization_literals_.length();
947}
948
949
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000950void LCodeGen::RecordSafepointWithLazyDeopt(
951 LInstruction* instr, SafepointMode safepoint_mode) {
952 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
953 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
954 } else {
955 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
956 RecordSafepointWithRegisters(
957 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
958 }
959}
960
961
ager@chromium.org378b34e2011-01-28 08:04:38 +0000962void LCodeGen::RecordSafepoint(
963 LPointerMap* pointers,
964 Safepoint::Kind kind,
965 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000966 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000967 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000968 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000969 Safepoint safepoint =
970 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000971 for (int i = 0; i < operands->length(); i++) {
972 LOperand* pointer = operands->at(i);
973 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000974 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000975 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000976 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000977 }
978 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000979}
980
981
982void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000983 Safepoint::DeoptMode mode) {
984 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000985}
986
987
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000988void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000989 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000990 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000991}
992
993
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000994void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
995 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000996 Safepoint::DeoptMode mode) {
997 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000998}
999
1000
1001void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001002 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001003 masm()->positions_recorder()->RecordPosition(position);
1004}
1005
1006
1007void LCodeGen::DoLabel(LLabel* label) {
1008 if (label->is_loop_header()) {
1009 Comment(";;; B%d - LOOP entry", label->block_id());
1010 } else {
1011 Comment(";;; B%d", label->block_id());
1012 }
1013 __ bind(label->label());
1014 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001015 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016}
1017
1018
1019void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001020 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001021}
1022
1023
1024void LCodeGen::DoGap(LGap* gap) {
1025 for (int i = LGap::FIRST_INNER_POSITION;
1026 i <= LGap::LAST_INNER_POSITION;
1027 i++) {
1028 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1029 LParallelMove* move = gap->GetParallelMove(inner_pos);
1030 if (move != NULL) DoParallelMove(move);
1031 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001032}
1033
1034
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001035void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1036 DoGap(instr);
1037}
1038
1039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001040void LCodeGen::DoParameter(LParameter* instr) {
1041 // Nothing to do.
1042}
1043
1044
1045void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001046 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001047 ASSERT(ToRegister(instr->result()).is(eax));
1048 switch (instr->hydrogen()->major_key()) {
1049 case CodeStub::RegExpConstructResult: {
1050 RegExpConstructResultStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001051 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001052 break;
1053 }
1054 case CodeStub::RegExpExec: {
1055 RegExpExecStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001056 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057 break;
1058 }
1059 case CodeStub::SubString: {
1060 SubStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001061 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062 break;
1063 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064 case CodeStub::NumberToString: {
1065 NumberToStringStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001066 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001067 break;
1068 }
1069 case CodeStub::StringAdd: {
1070 StringAddStub stub(NO_STRING_ADD_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001071 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001072 break;
1073 }
1074 case CodeStub::StringCompare: {
1075 StringCompareStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001076 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001077 break;
1078 }
1079 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001080 TranscendentalCacheStub stub(instr->transcendental_type(),
1081 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001082 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001083 break;
1084 }
1085 default:
1086 UNREACHABLE();
1087 }
1088}
1089
1090
1091void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1092 // Nothing to do.
1093}
1094
1095
1096void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001097 if (instr->hydrogen()->HasPowerOf2Divisor()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001098 Register dividend = ToRegister(instr->left());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001100 int32_t divisor =
1101 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001102
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001103 if (divisor < 0) divisor = -divisor;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001104
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001105 Label positive_dividend, done;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001106 __ test(dividend, Operand(dividend));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001107 __ j(not_sign, &positive_dividend, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001108 __ neg(dividend);
1109 __ and_(dividend, divisor - 1);
1110 __ neg(dividend);
1111 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001112 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001113 DeoptimizeIf(no_condition, instr->environment());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001114 } else {
1115 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001116 }
1117 __ bind(&positive_dividend);
1118 __ and_(dividend, divisor - 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001119 __ bind(&done);
1120 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001121 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001122 Register left_reg = ToRegister(instr->left());
1123 Register right_reg = ToRegister(instr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001124 Register result_reg = ToRegister(instr->result());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001125
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001126 ASSERT(left_reg.is(eax));
1127 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001128 ASSERT(!right_reg.is(eax));
1129 ASSERT(!right_reg.is(edx));
1130
1131 // Check for x % 0.
1132 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001133 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001134 DeoptimizeIf(zero, instr->environment());
1135 }
1136
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001137 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001138 __ j(zero, &remainder_eq_dividend, Label::kNear);
1139 __ j(sign, &slow, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001140
1141 __ test(right_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001142 __ j(not_sign, &both_positive, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001143 // The sign of the divisor doesn't matter.
1144 __ neg(right_reg);
1145
1146 __ bind(&both_positive);
1147 // If the dividend is smaller than the nonnegative
1148 // divisor, the dividend is the result.
1149 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001150 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001151
1152 // Check if the divisor is a PowerOfTwo integer.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001153 Register scratch = ToRegister(instr->temp());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001154 __ mov(scratch, right_reg);
1155 __ sub(Operand(scratch), Immediate(1));
1156 __ test(scratch, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001157 __ j(not_zero, &do_subtraction, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001158 __ and_(left_reg, Operand(scratch));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001159 __ jmp(&remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001160
1161 __ bind(&do_subtraction);
1162 const int kUnfolds = 3;
1163 // Try a few subtractions of the dividend.
1164 __ mov(scratch, left_reg);
1165 for (int i = 0; i < kUnfolds; i++) {
1166 // Reduce the dividend by the divisor.
1167 __ sub(left_reg, Operand(right_reg));
1168 // Check if the dividend is less than the divisor.
1169 __ cmp(left_reg, Operand(right_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001170 __ j(less, &remainder_eq_dividend, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001171 }
1172 __ mov(left_reg, scratch);
1173
1174 // Slow case, using idiv instruction.
1175 __ bind(&slow);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001176
1177 // Check for (kMinInt % -1).
1178 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1179 Label left_not_min_int;
1180 __ cmp(left_reg, kMinInt);
1181 __ j(not_zero, &left_not_min_int, Label::kNear);
1182 __ cmp(right_reg, -1);
1183 DeoptimizeIf(zero, instr->environment());
1184 __ bind(&left_not_min_int);
1185 }
1186
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001187 // Sign extend to edx.
1188 __ cdq();
1189
1190 // Check for (0 % -x) that will produce negative zero.
1191 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001192 Label positive_left;
1193 Label done;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001194 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001195 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001196 __ idiv(right_reg);
1197
1198 // Test the remainder for 0, because then the result would be -0.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001199 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001200 __ j(not_zero, &done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001201
1202 DeoptimizeIf(no_condition, instr->environment());
1203 __ bind(&positive_left);
1204 __ idiv(right_reg);
1205 __ bind(&done);
1206 } else {
1207 __ idiv(right_reg);
1208 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001209 __ jmp(&done, Label::kNear);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001210
1211 __ bind(&remainder_eq_dividend);
1212 __ mov(result_reg, left_reg);
1213
1214 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001215 }
1216}
1217
1218
1219void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001220 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001221 Register dividend = ToRegister(instr->left());
1222 int32_t divisor =
1223 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1224 int32_t test_value = 0;
1225 int32_t power = 0;
1226
1227 if (divisor > 0) {
1228 test_value = divisor - 1;
1229 power = WhichPowerOf2(divisor);
1230 } else {
1231 // Check for (0 / -x) that will produce negative zero.
1232 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1233 __ test(dividend, Operand(dividend));
1234 DeoptimizeIf(zero, instr->environment());
1235 }
1236 // Check for (kMinInt / -1).
1237 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1238 __ cmp(dividend, kMinInt);
1239 DeoptimizeIf(zero, instr->environment());
1240 }
1241 test_value = - divisor - 1;
1242 power = WhichPowerOf2(-divisor);
1243 }
1244
1245 if (test_value != 0) {
1246 // Deoptimize if remainder is not 0.
1247 __ test(dividend, Immediate(test_value));
1248 DeoptimizeIf(not_zero, instr->environment());
1249 __ sar(dividend, power);
1250 }
1251
1252 if (divisor < 0) __ neg(dividend);
1253
1254 return;
1255 }
1256
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001257 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001258 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001259 ASSERT(ToRegister(instr->left()).is(eax));
1260 ASSERT(!ToRegister(instr->right()).is(eax));
1261 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001262
1263 Register left_reg = eax;
1264
1265 // Check for x / 0.
1266 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001267 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 __ test(right_reg, ToOperand(right));
1269 DeoptimizeIf(zero, instr->environment());
1270 }
1271
1272 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001273 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001274 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001275 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001276 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001277 __ test(right_reg, ToOperand(right));
1278 DeoptimizeIf(sign, instr->environment());
1279 __ bind(&left_not_zero);
1280 }
1281
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001282 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001283 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001284 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001285 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001286 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001287 __ cmp(right_reg, -1);
1288 DeoptimizeIf(zero, instr->environment());
1289 __ bind(&left_not_min_int);
1290 }
1291
1292 // Sign extend to edx.
1293 __ cdq();
1294 __ idiv(right_reg);
1295
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001296 if (!instr->is_flooring()) {
1297 // Deoptimize if remainder is not 0.
1298 __ test(edx, Operand(edx));
1299 DeoptimizeIf(not_zero, instr->environment());
1300 } else {
1301 Label done;
1302 __ test(edx, edx);
1303 __ j(zero, &done, Label::kNear);
1304 __ xor_(edx, right_reg);
1305 __ sar(edx, 31);
1306 __ add(eax, edx);
1307 __ bind(&done);
1308 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001309}
1310
1311
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001312void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001313 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001314
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001315 Register dividend = ToRegister(instr->left());
1316 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001317 Register result = ToRegister(instr->result());
1318
1319 switch (divisor) {
1320 case 0:
1321 DeoptimizeIf(no_condition, instr->environment());
1322 return;
1323
1324 case 1:
1325 __ Move(result, dividend);
1326 return;
1327
1328 case -1:
1329 __ Move(result, dividend);
1330 __ neg(result);
1331 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1332 DeoptimizeIf(zero, instr->environment());
1333 }
1334 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1335 DeoptimizeIf(overflow, instr->environment());
1336 }
1337 return;
1338 }
1339
1340 uint32_t divisor_abs = abs(divisor);
1341 if (IsPowerOf2(divisor_abs)) {
1342 int32_t power = WhichPowerOf2(divisor_abs);
1343 if (divisor < 0) {
1344 // Input[dividend] is clobbered.
1345 // The sequence is tedious because neg(dividend) might overflow.
1346 __ mov(result, dividend);
1347 __ sar(dividend, 31);
1348 __ neg(result);
1349 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1350 DeoptimizeIf(zero, instr->environment());
1351 }
1352 __ shl(dividend, 32 - power);
1353 __ sar(result, power);
1354 __ not_(dividend);
1355 // Clear result.sign if dividend.sign is set.
1356 __ and_(result, dividend);
1357 } else {
1358 __ Move(result, dividend);
1359 __ sar(result, power);
1360 }
1361 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001362 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001363 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001364 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001365
1366 // Find b which: 2^b < divisor_abs < 2^(b+1).
1367 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1368 unsigned shift = 32 + b; // Precision +1bit (effectively).
1369 double multiplier_f =
1370 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1371 int64_t multiplier;
1372 if (multiplier_f - floor(multiplier_f) < 0.5) {
1373 multiplier = static_cast<int64_t>(floor(multiplier_f));
1374 } else {
1375 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1376 }
1377 // The multiplier is a uint32.
1378 ASSERT(multiplier > 0 &&
1379 multiplier < (static_cast<int64_t>(1) << 32));
1380 __ mov(scratch, dividend);
1381 if (divisor < 0 &&
1382 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1383 __ test(dividend, dividend);
1384 DeoptimizeIf(zero, instr->environment());
1385 }
1386 __ mov(edx, static_cast<int32_t>(multiplier));
1387 __ imul(edx);
1388 if (static_cast<int32_t>(multiplier) < 0) {
1389 __ add(edx, scratch);
1390 }
1391 Register reg_lo = eax;
1392 Register reg_byte_scratch = scratch;
1393 if (!reg_byte_scratch.is_byte_register()) {
1394 __ xchg(reg_lo, reg_byte_scratch);
1395 reg_lo = scratch;
1396 reg_byte_scratch = eax;
1397 }
1398 if (divisor < 0) {
1399 __ xor_(reg_byte_scratch, reg_byte_scratch);
1400 __ cmp(reg_lo, 0x40000000);
1401 __ setcc(above, reg_byte_scratch);
1402 __ neg(edx);
1403 __ sub(edx, reg_byte_scratch);
1404 } else {
1405 __ xor_(reg_byte_scratch, reg_byte_scratch);
1406 __ cmp(reg_lo, 0xC0000000);
1407 __ setcc(above_equal, reg_byte_scratch);
1408 __ add(edx, reg_byte_scratch);
1409 }
1410 __ sar(edx, shift - 32);
1411 }
1412}
1413
1414
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001415void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001416 Register left = ToRegister(instr->left());
1417 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001418
1419 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001420 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001421 }
1422
1423 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001424 // Try strength reductions on the multiplication.
1425 // All replacement instructions are at most as long as the imul
1426 // and have better latency.
1427 int constant = ToInteger32(LConstantOperand::cast(right));
1428 if (constant == -1) {
1429 __ neg(left);
1430 } else if (constant == 0) {
1431 __ xor_(left, Operand(left));
1432 } else if (constant == 2) {
1433 __ add(left, Operand(left));
1434 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1435 // If we know that the multiplication can't overflow, it's safe to
1436 // use instructions that don't set the overflow flag for the
1437 // multiplication.
1438 switch (constant) {
1439 case 1:
1440 // Do nothing.
1441 break;
1442 case 3:
1443 __ lea(left, Operand(left, left, times_2, 0));
1444 break;
1445 case 4:
1446 __ shl(left, 2);
1447 break;
1448 case 5:
1449 __ lea(left, Operand(left, left, times_4, 0));
1450 break;
1451 case 8:
1452 __ shl(left, 3);
1453 break;
1454 case 9:
1455 __ lea(left, Operand(left, left, times_8, 0));
1456 break;
1457 case 16:
1458 __ shl(left, 4);
1459 break;
1460 default:
1461 __ imul(left, left, constant);
1462 break;
1463 }
1464 } else {
1465 __ imul(left, left, constant);
1466 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001467 } else {
1468 __ imul(left, ToOperand(right));
1469 }
1470
1471 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1472 DeoptimizeIf(overflow, instr->environment());
1473 }
1474
1475 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1476 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001477 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001478 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001479 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001480 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001481 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001482 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001483 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1484 __ cmp(ToRegister(instr->temp()), Immediate(0));
1485 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001486 }
1487 } else {
1488 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001489 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001490 DeoptimizeIf(sign, instr->environment());
1491 }
1492 __ bind(&done);
1493 }
1494}
1495
1496
1497void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001498 LOperand* left = instr->left();
1499 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001500 ASSERT(left->Equals(instr->result()));
1501 ASSERT(left->IsRegister());
1502
1503 if (right->IsConstantOperand()) {
1504 int right_operand = ToInteger32(LConstantOperand::cast(right));
1505 switch (instr->op()) {
1506 case Token::BIT_AND:
1507 __ and_(ToRegister(left), right_operand);
1508 break;
1509 case Token::BIT_OR:
1510 __ or_(ToRegister(left), right_operand);
1511 break;
1512 case Token::BIT_XOR:
1513 __ xor_(ToRegister(left), right_operand);
1514 break;
1515 default:
1516 UNREACHABLE();
1517 break;
1518 }
1519 } else {
1520 switch (instr->op()) {
1521 case Token::BIT_AND:
1522 __ and_(ToRegister(left), ToOperand(right));
1523 break;
1524 case Token::BIT_OR:
1525 __ or_(ToRegister(left), ToOperand(right));
1526 break;
1527 case Token::BIT_XOR:
1528 __ xor_(ToRegister(left), ToOperand(right));
1529 break;
1530 default:
1531 UNREACHABLE();
1532 break;
1533 }
1534 }
1535}
1536
1537
1538void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001539 LOperand* left = instr->left();
1540 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001541 ASSERT(left->Equals(instr->result()));
1542 ASSERT(left->IsRegister());
1543 if (right->IsRegister()) {
1544 ASSERT(ToRegister(right).is(ecx));
1545
1546 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001547 case Token::ROR:
1548 __ ror_cl(ToRegister(left));
1549 if (instr->can_deopt()) {
1550 __ test(ToRegister(left), Immediate(0x80000000));
1551 DeoptimizeIf(not_zero, instr->environment());
1552 }
1553 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001554 case Token::SAR:
1555 __ sar_cl(ToRegister(left));
1556 break;
1557 case Token::SHR:
1558 __ shr_cl(ToRegister(left));
1559 if (instr->can_deopt()) {
1560 __ test(ToRegister(left), Immediate(0x80000000));
1561 DeoptimizeIf(not_zero, instr->environment());
1562 }
1563 break;
1564 case Token::SHL:
1565 __ shl_cl(ToRegister(left));
1566 break;
1567 default:
1568 UNREACHABLE();
1569 break;
1570 }
1571 } else {
1572 int value = ToInteger32(LConstantOperand::cast(right));
1573 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1574 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001575 case Token::ROR:
1576 if (shift_count == 0 && instr->can_deopt()) {
1577 __ test(ToRegister(left), Immediate(0x80000000));
1578 DeoptimizeIf(not_zero, instr->environment());
1579 } else {
1580 __ ror(ToRegister(left), shift_count);
1581 }
1582 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 case Token::SAR:
1584 if (shift_count != 0) {
1585 __ sar(ToRegister(left), shift_count);
1586 }
1587 break;
1588 case Token::SHR:
1589 if (shift_count == 0 && instr->can_deopt()) {
1590 __ test(ToRegister(left), Immediate(0x80000000));
1591 DeoptimizeIf(not_zero, instr->environment());
1592 } else {
1593 __ shr(ToRegister(left), shift_count);
1594 }
1595 break;
1596 case Token::SHL:
1597 if (shift_count != 0) {
1598 __ shl(ToRegister(left), shift_count);
1599 }
1600 break;
1601 default:
1602 UNREACHABLE();
1603 break;
1604 }
1605 }
1606}
1607
1608
1609void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001610 LOperand* left = instr->left();
1611 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001612 ASSERT(left->Equals(instr->result()));
1613
1614 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001615 __ sub(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001616 } else {
1617 __ sub(ToRegister(left), ToOperand(right));
1618 }
1619 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1620 DeoptimizeIf(overflow, instr->environment());
1621 }
1622}
1623
1624
1625void LCodeGen::DoConstantI(LConstantI* instr) {
1626 ASSERT(instr->result()->IsRegister());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001627 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001628}
1629
1630
1631void LCodeGen::DoConstantD(LConstantD* instr) {
1632 ASSERT(instr->result()->IsDoubleRegister());
1633 XMMRegister res = ToDoubleRegister(instr->result());
1634 double v = instr->value();
1635 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1636 // do so if the constant is -0.0.
1637 if (BitCast<uint64_t, double>(v) == 0) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001638 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001639 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001640 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001641 uint64_t int_val = BitCast<uint64_t, double>(v);
1642 int32_t lower = static_cast<int32_t>(int_val);
1643 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001644 if (CpuFeatures::IsSupported(SSE4_1)) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001645 CpuFeatures::Scope scope1(SSE2);
1646 CpuFeatures::Scope scope2(SSE4_1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001647 if (lower != 0) {
1648 __ Set(temp, Immediate(lower));
1649 __ movd(res, Operand(temp));
1650 __ Set(temp, Immediate(upper));
1651 __ pinsrd(res, Operand(temp), 1);
1652 } else {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001653 __ xorps(res, res);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001654 __ Set(temp, Immediate(upper));
1655 __ pinsrd(res, Operand(temp), 1);
1656 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001657 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001658 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001659 __ Set(temp, Immediate(upper));
1660 __ movd(res, Operand(temp));
1661 __ psllq(res, 32);
1662 if (lower != 0) {
1663 __ Set(temp, Immediate(lower));
1664 __ movd(xmm0, Operand(temp));
1665 __ por(res, xmm0);
1666 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001667 }
1668 }
1669}
1670
1671
1672void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001673 Register reg = ToRegister(instr->result());
1674 Handle<Object> handle = instr->value();
1675 if (handle->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001676 __ LoadHeapObject(reg, Handle<HeapObject>::cast(handle));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001677 } else {
1678 __ Set(reg, Immediate(handle));
1679 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001680}
1681
1682
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001683void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001684 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001685 Register array = ToRegister(instr->value());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001686 __ mov(result, FieldOperand(array, JSArray::kLengthOffset));
1687}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001688
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001689
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001690void LCodeGen::DoFixedArrayBaseLength(
1691 LFixedArrayBaseLength* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001692 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001693 Register array = ToRegister(instr->value());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001694 __ mov(result, FieldOperand(array, FixedArrayBase::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001695}
1696
1697
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001698void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1699 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001700 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001701 __ EnumLength(result, map);
1702}
1703
1704
whesse@chromium.org7b260152011-06-20 15:33:18 +00001705void LCodeGen::DoElementsKind(LElementsKind* instr) {
1706 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001707 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001708
1709 // Load map into |result|.
1710 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1711 // Load the map's "bit field 2" into |result|. We only need the first byte,
1712 // but the following masking takes care of that anyway.
1713 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1714 // Retrieve elements_kind from bit field 2.
1715 __ and_(result, Map::kElementsKindMask);
1716 __ shr(result, Map::kElementsKindShift);
1717}
1718
1719
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001720void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001721 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001722 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001723 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001724 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001725
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001726 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001727 // If the object is a smi return the object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001728 __ JumpIfSmi(input, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001729
1730 // If the object is not a value type, return the object.
1731 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001732 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001733 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
1734
1735 __ bind(&done);
1736}
1737
1738
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001739void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001740 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001741 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001742 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001743 Smi* index = instr->index();
1744 Label runtime, done;
1745 ASSERT(object.is(result));
1746 ASSERT(object.is(eax));
1747
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001748 __ test(object, Immediate(kSmiTagMask));
1749 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001750 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001751 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001752
1753 if (index->value() == 0) {
1754 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
1755 } else {
1756 if (index->value() < JSDate::kFirstUncachedField) {
1757 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1758 __ mov(scratch, Operand::StaticVariable(stamp));
1759 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
1760 __ j(not_equal, &runtime, Label::kNear);
1761 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
1762 kPointerSize * index->value()));
1763 __ jmp(&done);
1764 }
1765 __ bind(&runtime);
1766 __ PrepareCallCFunction(2, scratch);
1767 __ mov(Operand(esp, 0), object);
1768 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
1769 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1770 __ bind(&done);
1771 }
1772}
1773
1774
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001775void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1776 SeqStringSetCharGenerator::Generate(masm(),
1777 instr->encoding(),
1778 ToRegister(instr->string()),
1779 ToRegister(instr->index()),
1780 ToRegister(instr->value()));
1781}
1782
1783
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001784void LCodeGen::DoBitNotI(LBitNotI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001785 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001786 ASSERT(input->Equals(instr->result()));
1787 __ not_(ToRegister(input));
1788}
1789
1790
1791void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001792 __ push(ToOperand(instr->value()));
1793 ASSERT(ToRegister(instr->context()).is(esi));
1794 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001795
1796 if (FLAG_debug_code) {
1797 Comment("Unreachable code.");
1798 __ int3();
1799 }
1800}
1801
1802
1803void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001804 LOperand* left = instr->left();
1805 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001806 ASSERT(left->Equals(instr->result()));
1807
1808 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001809 __ add(ToOperand(left), ToInteger32Immediate(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001810 } else {
1811 __ add(ToRegister(left), ToOperand(right));
1812 }
1813
1814 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1815 DeoptimizeIf(overflow, instr->environment());
1816 }
1817}
1818
1819
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001820void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001821 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001822 LOperand* left = instr->left();
1823 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001824 ASSERT(left->Equals(instr->result()));
1825 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1826 if (instr->hydrogen()->representation().IsInteger32()) {
1827 Label return_left;
1828 Condition condition = (operation == HMathMinMax::kMathMin)
1829 ? less_equal
1830 : greater_equal;
1831 if (right->IsConstantOperand()) {
1832 Operand left_op = ToOperand(left);
1833 Immediate right_imm = ToInteger32Immediate(right);
1834 __ cmp(left_op, right_imm);
1835 __ j(condition, &return_left, Label::kNear);
1836 __ mov(left_op, right_imm);
1837 } else {
1838 Register left_reg = ToRegister(left);
1839 Operand right_op = ToOperand(right);
1840 __ cmp(left_reg, right_op);
1841 __ j(condition, &return_left, Label::kNear);
1842 __ mov(left_reg, right_op);
1843 }
1844 __ bind(&return_left);
1845 } else {
1846 ASSERT(instr->hydrogen()->representation().IsDouble());
1847 Label check_nan_left, check_zero, return_left, return_right;
1848 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1849 XMMRegister left_reg = ToDoubleRegister(left);
1850 XMMRegister right_reg = ToDoubleRegister(right);
1851 __ ucomisd(left_reg, right_reg);
1852 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1853 __ j(equal, &check_zero, Label::kNear); // left == right.
1854 __ j(condition, &return_left, Label::kNear);
1855 __ jmp(&return_right, Label::kNear);
1856
1857 __ bind(&check_zero);
1858 XMMRegister xmm_scratch = xmm0;
1859 __ xorps(xmm_scratch, xmm_scratch);
1860 __ ucomisd(left_reg, xmm_scratch);
1861 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1862 // At this point, both left and right are either 0 or -0.
1863 if (operation == HMathMinMax::kMathMin) {
1864 __ orpd(left_reg, right_reg);
1865 } else {
1866 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1867 __ addsd(left_reg, right_reg);
1868 }
1869 __ jmp(&return_left, Label::kNear);
1870
1871 __ bind(&check_nan_left);
1872 __ ucomisd(left_reg, left_reg); // NaN check.
1873 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
1874 __ bind(&return_right);
1875 __ movsd(left_reg, right_reg);
1876
1877 __ bind(&return_left);
1878 }
1879}
1880
1881
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001882void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001883 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001884 XMMRegister left = ToDoubleRegister(instr->left());
1885 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001886 XMMRegister result = ToDoubleRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001887 // Modulo uses a fixed result register.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001888 ASSERT(instr->op() == Token::MOD || left.is(result));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001889 switch (instr->op()) {
1890 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001891 __ addsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001892 break;
1893 case Token::SUB:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001894 __ subsd(left, right);
1895 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001897 __ mulsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001898 break;
1899 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001900 __ divsd(left, right);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 break;
1902 case Token::MOD: {
1903 // Pass two doubles as arguments on the stack.
1904 __ PrepareCallCFunction(4, eax);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001905 __ movdbl(Operand(esp, 0 * kDoubleSize), left);
1906 __ movdbl(Operand(esp, 1 * kDoubleSize), right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 __ CallCFunction(
1908 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1909 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001910
1911 // Return value is in st(0) on ia32.
1912 // Store it into the (fixed) result register.
1913 __ sub(Operand(esp), Immediate(kDoubleSize));
1914 __ fstp_d(Operand(esp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001915 __ movdbl(result, Operand(esp, 0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001916 __ add(Operand(esp), Immediate(kDoubleSize));
1917 break;
1918 }
1919 default:
1920 UNREACHABLE();
1921 break;
1922 }
1923}
1924
1925
1926void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001927 ASSERT(ToRegister(instr->context()).is(esi));
1928 ASSERT(ToRegister(instr->left()).is(edx));
1929 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001930 ASSERT(ToRegister(instr->result()).is(eax));
1931
danno@chromium.org40cb8782011-05-25 07:58:50 +00001932 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001933 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001934 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001935}
1936
1937
1938int LCodeGen::GetNextEmittedBlock(int block) {
1939 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1940 LLabel* label = chunk_->GetLabel(i);
1941 if (!label->HasReplacement()) return i;
1942 }
1943 return -1;
1944}
1945
1946
1947void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1948 int next_block = GetNextEmittedBlock(current_block_);
1949 right_block = chunk_->LookupDestination(right_block);
1950 left_block = chunk_->LookupDestination(left_block);
1951
1952 if (right_block == left_block) {
1953 EmitGoto(left_block);
1954 } else if (left_block == next_block) {
1955 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1956 } else if (right_block == next_block) {
1957 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1958 } else {
1959 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1960 __ jmp(chunk_->GetAssemblyLabel(right_block));
1961 }
1962}
1963
1964
1965void LCodeGen::DoBranch(LBranch* instr) {
1966 int true_block = chunk_->LookupDestination(instr->true_block_id());
1967 int false_block = chunk_->LookupDestination(instr->false_block_id());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001968 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001969
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001970 Representation r = instr->hydrogen()->value()->representation();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001971 if (r.IsInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001972 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001973 __ test(reg, Operand(reg));
1974 EmitBranch(true_block, false_block, not_zero);
1975 } else if (r.IsDouble()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001976 XMMRegister reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001977 __ xorps(xmm0, xmm0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001978 __ ucomisd(reg, xmm0);
1979 EmitBranch(true_block, false_block, not_equal);
1980 } else {
1981 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001982 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001983 HType type = instr->hydrogen()->value()->type();
1984 if (type.IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 __ cmp(reg, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986 EmitBranch(true_block, false_block, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001987 } else if (type.IsSmi()) {
1988 __ test(reg, Operand(reg));
1989 EmitBranch(true_block, false_block, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 } else {
1991 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1992 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1993
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001994 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1995 // Avoid deopts in the case where we've never executed this path before.
1996 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001997
vegorov@chromium.org7943d462011-08-01 11:41:52 +00001998 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1999 // undefined -> false.
2000 __ cmp(reg, factory()->undefined_value());
2001 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002002 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002003 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2004 // true -> true.
2005 __ cmp(reg, factory()->true_value());
2006 __ j(equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002007 // false -> false.
2008 __ cmp(reg, factory()->false_value());
2009 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002010 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002011 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2012 // 'null' -> false.
2013 __ cmp(reg, factory()->null_value());
2014 __ j(equal, false_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002015 }
2016
2017 if (expected.Contains(ToBooleanStub::SMI)) {
2018 // Smis: 0 -> false, all other -> true.
2019 __ test(reg, Operand(reg));
2020 __ j(equal, false_label);
2021 __ JumpIfSmi(reg, true_label);
2022 } else if (expected.NeedsMap()) {
2023 // If we need a map later and have a Smi -> deopt.
2024 __ test(reg, Immediate(kSmiTagMask));
2025 DeoptimizeIf(zero, instr->environment());
2026 }
2027
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002028 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002029 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002030 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002031 ASSERT(!map.is(reg));
2032 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002033
2034 if (expected.CanBeUndetectable()) {
2035 // Undetectable -> false.
2036 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2037 1 << Map::kIsUndetectable);
2038 __ j(not_zero, false_label);
2039 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002040 }
2041
2042 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2043 // spec object -> true.
2044 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
2045 __ j(above_equal, true_label);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002046 }
2047
2048 if (expected.Contains(ToBooleanStub::STRING)) {
2049 // String value -> false iff empty.
2050 Label not_string;
2051 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2052 __ j(above_equal, &not_string, Label::kNear);
2053 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2054 __ j(not_zero, true_label);
2055 __ jmp(false_label);
2056 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002057 }
2058
2059 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2060 // heap number -> false iff +0, -0, or NaN.
2061 Label not_heap_number;
2062 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2063 factory()->heap_number_map());
2064 __ j(not_equal, &not_heap_number, Label::kNear);
2065 __ fldz();
2066 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
2067 __ FCmp();
2068 __ j(zero, false_label);
2069 __ jmp(true_label);
2070 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002071 }
2072
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002073 // We've seen something for the first time -> deopt.
2074 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002075 }
2076 }
2077}
2078
2079
ager@chromium.org04921a82011-06-27 13:21:41 +00002080void LCodeGen::EmitGoto(int block) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002081 block = chunk_->LookupDestination(block);
2082 int next_block = GetNextEmittedBlock(current_block_);
2083 if (block != next_block) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002084 __ jmp(chunk_->GetAssemblyLabel(block));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002085 }
2086}
2087
2088
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002089void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002090 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002091}
2092
2093
2094Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2095 Condition cond = no_condition;
2096 switch (op) {
2097 case Token::EQ:
2098 case Token::EQ_STRICT:
2099 cond = equal;
2100 break;
2101 case Token::LT:
2102 cond = is_unsigned ? below : less;
2103 break;
2104 case Token::GT:
2105 cond = is_unsigned ? above : greater;
2106 break;
2107 case Token::LTE:
2108 cond = is_unsigned ? below_equal : less_equal;
2109 break;
2110 case Token::GTE:
2111 cond = is_unsigned ? above_equal : greater_equal;
2112 break;
2113 case Token::IN:
2114 case Token::INSTANCEOF:
2115 default:
2116 UNREACHABLE();
2117 }
2118 return cond;
2119}
2120
2121
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002122void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002123 LOperand* left = instr->left();
2124 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002125 int false_block = chunk_->LookupDestination(instr->false_block_id());
2126 int true_block = chunk_->LookupDestination(instr->true_block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002127 Condition cc = TokenToCondition(instr->op(), instr->is_double());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002128 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002129
2130 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2131 // We can statically evaluate the comparison.
2132 double left_val = ToDouble(LConstantOperand::cast(left));
2133 double right_val = ToDouble(LConstantOperand::cast(right));
2134 int next_block =
2135 EvalComparison(instr->op(), left_val, right_val) ? true_block
2136 : false_block;
2137 EmitGoto(next_block);
2138 } else {
2139 if (instr->is_double()) {
2140 // Don't base result on EFLAGS when a NaN is involved. Instead
2141 // jump to the false block.
2142 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2143 __ j(parity_even, chunk_->GetAssemblyLabel(false_block));
2144 } else {
2145 if (right->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002146 __ cmp(ToRegister(left), ToInteger32Immediate(right));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002147 } else if (left->IsConstantOperand()) {
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00002148 __ cmp(ToOperand(right), ToInteger32Immediate(left));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002149 // We transposed the operands. Reverse the condition.
2150 cc = ReverseCondition(cc);
2151 } else {
2152 __ cmp(ToRegister(left), ToOperand(right));
2153 }
2154 }
2155 EmitBranch(true_block, false_block, cc);
2156 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002157}
2158
2159
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002160void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002161 Register left = ToRegister(instr->left());
2162 Operand right = ToOperand(instr->right());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002163 int false_block = chunk_->LookupDestination(instr->false_block_id());
2164 int true_block = chunk_->LookupDestination(instr->true_block_id());
2165
2166 __ cmp(left, Operand(right));
2167 EmitBranch(true_block, false_block, equal);
2168}
2169
2170
whesse@chromium.org7b260152011-06-20 15:33:18 +00002171void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002172 Register left = ToRegister(instr->left());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002173 int true_block = chunk_->LookupDestination(instr->true_block_id());
2174 int false_block = chunk_->LookupDestination(instr->false_block_id());
2175
2176 __ cmp(left, instr->hydrogen()->right());
2177 EmitBranch(true_block, false_block, equal);
2178}
2179
2180
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002181void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002182 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002183 int false_block = chunk_->LookupDestination(instr->false_block_id());
2184
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002185 // If the expression is known to be untagged or a smi, then it's definitely
2186 // not null, and it can't be a an undetectable object.
2187 if (instr->hydrogen()->representation().IsSpecialization() ||
2188 instr->hydrogen()->type().IsSmi()) {
2189 EmitGoto(false_block);
2190 return;
2191 }
2192
2193 int true_block = chunk_->LookupDestination(instr->true_block_id());
2194 Handle<Object> nil_value = instr->nil() == kNullValue ?
2195 factory()->null_value() :
2196 factory()->undefined_value();
2197 __ cmp(reg, nil_value);
2198 if (instr->kind() == kStrictEquality) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 EmitBranch(true_block, false_block, equal);
2200 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002201 Handle<Object> other_nil_value = instr->nil() == kNullValue ?
2202 factory()->undefined_value() :
2203 factory()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002204 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2205 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2206 __ j(equal, true_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002207 __ cmp(reg, other_nil_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002208 __ j(equal, true_label);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002209 __ JumpIfSmi(reg, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002210 // Check for undetectable objects by looking in the bit field in
2211 // the map. The object has already been smi checked.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002212 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002213 __ mov(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2214 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
2215 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
2216 EmitBranch(true_block, false_block, not_zero);
2217 }
2218}
2219
2220
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002221Condition LCodeGen::EmitIsObject(Register input,
2222 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002223 Label* is_not_object,
2224 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002225 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002228 __ j(equal, is_object);
2229
2230 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2231 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002232 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2233 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002234 __ j(not_zero, is_not_object);
2235
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002236 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2237 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002238 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002239 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002240 return below_equal;
2241}
2242
2243
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002244void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002245 Register reg = ToRegister(instr->value());
2246 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002247
2248 int true_block = chunk_->LookupDestination(instr->true_block_id());
2249 int false_block = chunk_->LookupDestination(instr->false_block_id());
2250 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2251 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2252
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002253 Condition true_cond = EmitIsObject(reg, temp, false_label, true_label);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002254
2255 EmitBranch(true_block, false_block, true_cond);
2256}
2257
2258
erikcorry0ad885c2011-11-21 13:51:57 +00002259Condition LCodeGen::EmitIsString(Register input,
2260 Register temp1,
2261 Label* is_not_string) {
2262 __ JumpIfSmi(input, is_not_string);
2263
2264 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2265
2266 return cond;
2267}
2268
2269
2270void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002271 Register reg = ToRegister(instr->value());
2272 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002273
2274 int true_block = chunk_->LookupDestination(instr->true_block_id());
2275 int false_block = chunk_->LookupDestination(instr->false_block_id());
2276 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2277
2278 Condition true_cond = EmitIsString(reg, temp, false_label);
2279
2280 EmitBranch(true_block, false_block, true_cond);
2281}
2282
2283
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002284void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002285 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002286
2287 int true_block = chunk_->LookupDestination(instr->true_block_id());
2288 int false_block = chunk_->LookupDestination(instr->false_block_id());
2289
2290 __ test(input, Immediate(kSmiTagMask));
2291 EmitBranch(true_block, false_block, zero);
2292}
2293
2294
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002295void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002296 Register input = ToRegister(instr->value());
2297 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002298
2299 int true_block = chunk_->LookupDestination(instr->true_block_id());
2300 int false_block = chunk_->LookupDestination(instr->false_block_id());
2301
2302 STATIC_ASSERT(kSmiTag == 0);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002303 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002304 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2305 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2306 1 << Map::kIsUndetectable);
2307 EmitBranch(true_block, false_block, not_zero);
2308}
2309
2310
erikcorry0ad885c2011-11-21 13:51:57 +00002311static Condition ComputeCompareCondition(Token::Value op) {
2312 switch (op) {
2313 case Token::EQ_STRICT:
2314 case Token::EQ:
2315 return equal;
2316 case Token::LT:
2317 return less;
2318 case Token::GT:
2319 return greater;
2320 case Token::LTE:
2321 return less_equal;
2322 case Token::GTE:
2323 return greater_equal;
2324 default:
2325 UNREACHABLE();
2326 return no_condition;
2327 }
2328}
2329
2330
2331void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2332 Token::Value op = instr->op();
2333 int true_block = chunk_->LookupDestination(instr->true_block_id());
2334 int false_block = chunk_->LookupDestination(instr->false_block_id());
2335
2336 Handle<Code> ic = CompareIC::GetUninitialized(op);
2337 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2338
2339 Condition condition = ComputeCompareCondition(op);
2340 __ test(eax, Operand(eax));
2341
2342 EmitBranch(true_block, false_block, condition);
2343}
2344
2345
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002346static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002347 InstanceType from = instr->from();
2348 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002349 if (from == FIRST_TYPE) return to;
2350 ASSERT(from == to || to == LAST_TYPE);
2351 return from;
2352}
2353
2354
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002355static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002356 InstanceType from = instr->from();
2357 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002358 if (from == to) return equal;
2359 if (to == LAST_TYPE) return above_equal;
2360 if (from == FIRST_TYPE) return below_equal;
2361 UNREACHABLE();
2362 return equal;
2363}
2364
2365
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002366void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002367 Register input = ToRegister(instr->value());
2368 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002369
2370 int true_block = chunk_->LookupDestination(instr->true_block_id());
2371 int false_block = chunk_->LookupDestination(instr->false_block_id());
2372
2373 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2374
whesse@chromium.org7b260152011-06-20 15:33:18 +00002375 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002376
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002377 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
2378 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002379}
2380
2381
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002382void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002383 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002384 Register result = ToRegister(instr->result());
2385
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002386 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002387
2388 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2389 __ IndexFromHash(result, result);
2390}
2391
2392
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002393void LCodeGen::DoHasCachedArrayIndexAndBranch(
2394 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002395 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002396
2397 int true_block = chunk_->LookupDestination(instr->true_block_id());
2398 int false_block = chunk_->LookupDestination(instr->false_block_id());
2399
2400 __ test(FieldOperand(input, String::kHashFieldOffset),
2401 Immediate(String::kContainsCachedArrayIndexMask));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002402 EmitBranch(true_block, false_block, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002403}
2404
2405
2406// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002407// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002408void LCodeGen::EmitClassOfTest(Label* is_true,
2409 Label* is_false,
2410 Handle<String>class_name,
2411 Register input,
2412 Register temp,
2413 Register temp2) {
2414 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002415 ASSERT(!input.is(temp2));
2416 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002417 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002418
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002419 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002420 // Assuming the following assertions, we can use the same compares to test
2421 // for both being a function type and being in the object type range.
2422 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2423 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2424 FIRST_SPEC_OBJECT_TYPE + 1);
2425 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2426 LAST_SPEC_OBJECT_TYPE - 1);
2427 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2428 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2429 __ j(below, is_false);
2430 __ j(equal, is_true);
2431 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2432 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002433 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002434 // Faster code path to avoid two compares: subtract lower bound from the
2435 // actual type and do a signed compare with the width of the type range.
2436 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002437 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002438 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002439 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2440 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002441 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002442 }
2443
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002444 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002445 // Check if the constructor in the map is a function.
2446 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002447 // Objects with a non-function constructor have class 'Object'.
2448 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002449 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002450 __ j(not_equal, is_true);
2451 } else {
2452 __ j(not_equal, is_false);
2453 }
2454
2455 // temp now contains the constructor function. Grab the
2456 // instance class name from there.
2457 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2458 __ mov(temp, FieldOperand(temp,
2459 SharedFunctionInfo::kInstanceClassNameOffset));
2460 // The class name we are testing against is a symbol because it's a literal.
2461 // The name in the constructor is a symbol because of the way the context is
2462 // booted. This routine isn't expected to work for random API-created
2463 // classes and it doesn't have to because you can't access it with natives
2464 // syntax. Since both sides are symbols it is sufficient to use an identity
2465 // comparison.
2466 __ cmp(temp, class_name);
2467 // End with the answer in the z flag.
2468}
2469
2470
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002471void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002472 Register input = ToRegister(instr->value());
2473 Register temp = ToRegister(instr->temp());
2474 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002475
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002476 Handle<String> class_name = instr->hydrogen()->class_name();
2477
2478 int true_block = chunk_->LookupDestination(instr->true_block_id());
2479 int false_block = chunk_->LookupDestination(instr->false_block_id());
2480
2481 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2482 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2483
2484 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2485
2486 EmitBranch(true_block, false_block, equal);
2487}
2488
2489
2490void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002491 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 int true_block = instr->true_block_id();
2493 int false_block = instr->false_block_id();
2494
2495 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
2496 EmitBranch(true_block, false_block, equal);
2497}
2498
2499
2500void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002501 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002502 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002503 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002504 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002505
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002506 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002507 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002508 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002509 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002510 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002511 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002513 __ bind(&done);
2514}
2515
2516
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002517void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2518 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2519 public:
2520 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2521 LInstanceOfKnownGlobal* instr)
2522 : LDeferredCode(codegen), instr_(instr) { }
2523 virtual void Generate() {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002524 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002525 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002526 virtual LInstruction* instr() { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002527 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002528 private:
2529 LInstanceOfKnownGlobal* instr_;
2530 Label map_check_;
2531 };
2532
2533 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002534 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002535
2536 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002537 Register object = ToRegister(instr->value());
2538 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002539
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002540 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002541 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002542
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002543 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002544 // hole value will be patched to the last map/result pair generated by the
2545 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002546 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002547 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002548 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2549 __ bind(deferred->map_check()); // Label for calculating code patching.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002550 Handle<JSGlobalPropertyCell> cache_cell =
2551 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2552 __ cmp(map, Operand::Cell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002553 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002554 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002555 __ jmp(&done);
2556
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002557 // The inlined call site cache did not match. Check for null and string
2558 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002559 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002560 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002561 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002562 __ j(equal, &false_result);
2563
2564 // String values are not instances of anything.
2565 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2566 __ j(is_string, &false_result);
2567
2568 // Go to the deferred code.
2569 __ jmp(deferred->entry());
2570
2571 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002572 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002573
2574 // Here result has either true or false. Deferred code also produces true or
2575 // false object.
2576 __ bind(deferred->exit());
2577 __ bind(&done);
2578}
2579
2580
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002581void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2582 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002583 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002584
2585 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2586 flags = static_cast<InstanceofStub::Flags>(
2587 flags | InstanceofStub::kArgsInRegisters);
2588 flags = static_cast<InstanceofStub::Flags>(
2589 flags | InstanceofStub::kCallSiteInlineCheck);
2590 flags = static_cast<InstanceofStub::Flags>(
2591 flags | InstanceofStub::kReturnTrueFalseObject);
2592 InstanceofStub stub(flags);
2593
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002594 // Get the temp register reserved by the instruction. This needs to be a
2595 // register which is pushed last by PushSafepointRegisters as top of the
2596 // stack is used to pass the offset to the location of the map check to
2597 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002598 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002599 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002600 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002601 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002602 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002603 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002604 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002605 CallCodeGeneric(stub.GetCode(),
2606 RelocInfo::CODE_TARGET,
2607 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002608 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002609 // Get the deoptimization index of the LLazyBailout-environment that
2610 // corresponds to this instruction.
2611 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002612 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2613
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002614 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002615 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002616}
2617
2618
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002619void LCodeGen::DoCmpT(LCmpT* instr) {
2620 Token::Value op = instr->op();
2621
2622 Handle<Code> ic = CompareIC::GetUninitialized(op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002623 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002624
2625 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002626 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002627 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002628 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002629 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002630 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002631 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002632 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002633 __ bind(&done);
2634}
2635
2636
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002637void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002638 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002639 // Preserve the return value on the stack and rely on the runtime call
2640 // to return the value in the same register. We're leaving the code
2641 // managed by the register allocator and tearing down the frame, it's
2642 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002643 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002644 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002645 __ CallRuntime(Runtime::kTraceExit, 1);
2646 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002647 if (dynamic_frame_alignment_) {
2648 // Fetch the state of the dynamic frame alignment.
2649 __ mov(edx, Operand(ebp,
2650 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
2651 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002652 if (NeedsEagerFrame()) {
2653 __ mov(esp, ebp);
2654 __ pop(ebp);
2655 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002656 if (dynamic_frame_alignment_) {
2657 Label no_padding;
2658 __ cmp(edx, Immediate(kNoAlignmentPadding));
2659 __ j(equal, &no_padding);
2660 if (FLAG_debug_code) {
2661 __ cmp(Operand(esp, (GetParameterCount() + 2) * kPointerSize),
2662 Immediate(kAlignmentZapValue));
2663 __ Assert(equal, "expected alignment marker");
2664 }
2665 __ Ret((GetParameterCount() + 2) * kPointerSize, ecx);
2666 __ bind(&no_padding);
2667 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002668 if (info()->IsStub()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002669 __ Ret();
2670 } else {
2671 __ Ret((GetParameterCount() + 1) * kPointerSize, ecx);
2672 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002673}
2674
2675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002676void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002677 Register result = ToRegister(instr->result());
2678 __ mov(result, Operand::Cell(instr->hydrogen()->cell()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002679 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002680 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002681 DeoptimizeIf(equal, instr->environment());
2682 }
2683}
2684
2685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002686void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2687 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002688 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002689 ASSERT(ToRegister(instr->result()).is(eax));
2690
2691 __ mov(ecx, instr->name());
2692 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2693 RelocInfo::CODE_TARGET_CONTEXT;
2694 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002695 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002696}
2697
2698
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002699void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002700 Register value = ToRegister(instr->value());
2701 Handle<JSGlobalPropertyCell> cell_handle = instr->hydrogen()->cell();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002702
2703 // If the cell we are storing to contains the hole it could have
2704 // been deleted from the property dictionary. In that case, we need
2705 // to update the property details in the property dictionary to mark
2706 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002707 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002708 __ cmp(Operand::Cell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00002709 DeoptimizeIf(equal, instr->environment());
2710 }
2711
2712 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002713 __ mov(Operand::Cell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002714 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002715}
2716
2717
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002718void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2719 ASSERT(ToRegister(instr->context()).is(esi));
2720 ASSERT(ToRegister(instr->global_object()).is(edx));
2721 ASSERT(ToRegister(instr->value()).is(eax));
2722
2723 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002724 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002725 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2726 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002727 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002728}
2729
2730
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002731void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002732 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002733 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002734 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002735
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002736 if (instr->hydrogen()->RequiresHoleCheck()) {
2737 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002738 if (instr->hydrogen()->DeoptimizesOnHole()) {
2739 DeoptimizeIf(equal, instr->environment());
2740 } else {
2741 Label is_not_hole;
2742 __ j(not_equal, &is_not_hole, Label::kNear);
2743 __ mov(result, factory()->undefined_value());
2744 __ bind(&is_not_hole);
2745 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002746 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002747}
2748
2749
2750void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2751 Register context = ToRegister(instr->context());
2752 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002753
2754 Label skip_assignment;
2755
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002756 Operand target = ContextOperand(context, instr->slot_index());
2757 if (instr->hydrogen()->RequiresHoleCheck()) {
2758 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002759 if (instr->hydrogen()->DeoptimizesOnHole()) {
2760 DeoptimizeIf(equal, instr->environment());
2761 } else {
2762 __ j(not_equal, &skip_assignment, Label::kNear);
2763 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002764 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002765
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002766 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002767 if (instr->hydrogen()->NeedsWriteBarrier()) {
2768 HType type = instr->hydrogen()->value()->type();
2769 SmiCheck check_needed =
2770 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002771 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002772 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002773 __ RecordWriteContextSlot(context,
2774 offset,
2775 value,
2776 temp,
2777 kSaveFPRegs,
2778 EMIT_REMEMBERED_SET,
2779 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002780 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002781
2782 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002783}
2784
2785
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002786void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002787 Register object = ToRegister(instr->object());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002788 Register result = ToRegister(instr->result());
2789 if (instr->hydrogen()->is_in_object()) {
2790 __ mov(result, FieldOperand(object, instr->hydrogen()->offset()));
2791 } else {
2792 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2793 __ mov(result, FieldOperand(result, instr->hydrogen()->offset()));
2794 }
2795}
2796
2797
lrn@chromium.org1c092762011-05-09 09:42:16 +00002798void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2799 Register object,
2800 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002801 Handle<String> name,
2802 LEnvironment* env) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002803 LookupResult lookup(isolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002804 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002805 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002806 if (lookup.IsField()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002807 int index = lookup.GetLocalFieldIndexFromMap(*type);
2808 int offset = index * kPointerSize;
2809 if (index < 0) {
2810 // Negative property indices are in-object properties, indexed
2811 // from the end of the fixed part of the object.
2812 __ mov(result, FieldOperand(object, offset + type->instance_size()));
2813 } else {
2814 // Non-negative property indices are in the properties array.
2815 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
2816 __ mov(result, FieldOperand(result, offset + FixedArray::kHeaderSize));
2817 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002818 } else if (lookup.IsConstantFunction()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002819 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002820 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002821 } else {
2822 // Negative lookup.
2823 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002824 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002825 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002826 while (*current != heap->null_value()) {
2827 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002828 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002829 Handle<Map>(current->map()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002830 DeoptimizeIf(not_equal, env);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002831 current =
2832 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002833 }
2834 __ mov(result, factory()->undefined_value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002835 }
2836}
2837
2838
2839void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
2840 ASSERT(!operand->IsDoubleRegister());
2841 if (operand->IsConstantOperand()) {
2842 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
2843 if (object->IsSmi()) {
2844 __ Push(Handle<Smi>::cast(object));
2845 } else {
2846 __ PushHeapObject(Handle<HeapObject>::cast(object));
2847 }
2848 } else if (operand->IsRegister()) {
2849 __ push(ToRegister(operand));
2850 } else {
2851 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002852 }
2853}
2854
2855
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002856// Check for cases where EmitLoadFieldOrConstantFunction needs to walk the
2857// prototype chain, which causes unbounded code generation.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002858static bool CompactEmit(SmallMapList* list,
2859 Handle<String> name,
2860 int i,
2861 Isolate* isolate) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002862 Handle<Map> map = list->at(i);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002863 // If the map has ElementsKind transitions, we will generate map checks
2864 // for each kind in __ CompareMap(..., ALLOW_ELEMENTS_TRANSITION_MAPS).
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002865 if (map->HasElementsTransition()) return false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002866 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002867 map->LookupDescriptor(NULL, *name, &lookup);
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002868 return lookup.IsField() || lookup.IsConstantFunction();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002869}
2870
2871
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002872void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2873 Register object = ToRegister(instr->object());
2874 Register result = ToRegister(instr->result());
2875
2876 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002877 bool need_generic = instr->hydrogen()->need_generic();
2878
2879 if (map_count == 0 && !need_generic) {
2880 DeoptimizeIf(no_condition, instr->environment());
2881 return;
2882 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002883 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002884 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002885 bool all_are_compact = true;
2886 for (int i = 0; i < map_count; ++i) {
2887 if (!CompactEmit(instr->hydrogen()->types(), name, i, isolate())) {
2888 all_are_compact = false;
2889 break;
2890 }
2891 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002892 for (int i = 0; i < map_count; ++i) {
2893 bool last = (i == map_count - 1);
2894 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002895 Label check_passed;
2896 __ CompareMap(object, map, &check_passed, ALLOW_ELEMENT_TRANSITION_MAPS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002897 if (last && !need_generic) {
2898 DeoptimizeIf(not_equal, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002899 __ bind(&check_passed);
2900 EmitLoadFieldOrConstantFunction(
2901 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002902 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002903 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002904 bool compact = all_are_compact ? true :
2905 CompactEmit(instr->hydrogen()->types(), name, i, isolate());
2906 __ j(not_equal, &next, compact ? Label::kNear : Label::kFar);
2907 __ bind(&check_passed);
2908 EmitLoadFieldOrConstantFunction(
2909 result, object, map, name, instr->environment());
2910 __ jmp(&done, all_are_compact ? Label::kNear : Label::kFar);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002911 __ bind(&next);
2912 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002913 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002914 if (need_generic) {
2915 __ mov(ecx, name);
2916 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2917 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2918 }
2919 __ bind(&done);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002920}
2921
2922
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002923void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002924 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002925 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002926 ASSERT(ToRegister(instr->result()).is(eax));
2927
2928 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002929 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002930 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002931}
2932
2933
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002934void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2935 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002936 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002937 Register result = ToRegister(instr->result());
2938
2939 // Check that the function really is a function.
2940 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2941 DeoptimizeIf(not_equal, instr->environment());
2942
2943 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002944 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002945 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
2946 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002947 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002948
2949 // Get the prototype or initial map from the function.
2950 __ mov(result,
2951 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2952
2953 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002954 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002955 DeoptimizeIf(equal, instr->environment());
2956
2957 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002958 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002959 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002960 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002961
2962 // Get the prototype from the initial map.
2963 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002964 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002965
2966 // Non-instance prototype: Fetch prototype from constructor field
2967 // in the function's map.
2968 __ bind(&non_instance);
2969 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
2970
2971 // All done.
2972 __ bind(&done);
2973}
2974
2975
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002976void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002977 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002978 Register input = ToRegister(instr->object());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002979 __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002980 if (FLAG_debug_code) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002981 Label done, ok, fail;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002982 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002983 Immediate(factory()->fixed_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002984 __ j(equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002985 __ cmp(FieldOperand(result, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002986 Immediate(factory()->fixed_cow_array_map()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002987 __ j(equal, &done, Label::kNear);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002988 Register temp((result.is(eax)) ? ebx : eax);
2989 __ push(temp);
2990 __ mov(temp, FieldOperand(result, HeapObject::kMapOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002991 __ movzx_b(temp, FieldOperand(temp, Map::kBitField2Offset));
2992 __ and_(temp, Map::kElementsKindMask);
2993 __ shr(temp, Map::kElementsKindShift);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002994 __ cmp(temp, GetInitialFastElementsKind());
2995 __ j(less, &fail, Label::kNear);
2996 __ cmp(temp, TERMINAL_FAST_ELEMENTS_KIND);
2997 __ j(less_equal, &ok, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002998 __ cmp(temp, FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002999 __ j(less, &fail, Label::kNear);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003000 __ cmp(temp, LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003001 __ j(less_equal, &ok, Label::kNear);
3002 __ bind(&fail);
3003 __ Abort("Check for fast or external elements failed.");
3004 __ bind(&ok);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003005 __ pop(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003006 __ bind(&done);
3007 }
3008}
3009
3010
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003011void LCodeGen::DoLoadExternalArrayPointer(
3012 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003013 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003014 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003015 __ mov(result, FieldOperand(input,
3016 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003017}
3018
3019
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003020void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3021 Register arguments = ToRegister(instr->arguments());
3022 Register length = ToRegister(instr->length());
3023 Operand index = ToOperand(instr->index());
3024 Register result = ToRegister(instr->result());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003025 // There are two words between the frame pointer and the last argument.
3026 // Subtracting from length accounts for one of them add one more.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003027 __ sub(length, index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003028 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3029}
3030
3031
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003032void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003033 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003034 LOperand* key = instr->key();
3035 if (!key->IsConstantOperand() &&
3036 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3037 elements_kind)) {
3038 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003039 }
3040 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003041 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003042 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003043 instr->hydrogen()->key()->representation(),
3044 elements_kind,
3045 0,
3046 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003047 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003048 if (CpuFeatures::IsSupported(SSE2)) {
3049 CpuFeatures::Scope scope(SSE2);
3050 XMMRegister result(ToDoubleRegister(instr->result()));
3051 __ movss(result, operand);
3052 __ cvtss2sd(result, result);
3053 } else {
3054 __ fld_s(operand);
3055 HandleX87FPReturnValue(instr);
3056 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003057 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003058 if (CpuFeatures::IsSupported(SSE2)) {
3059 CpuFeatures::Scope scope(SSE2);
3060 __ movdbl(ToDoubleRegister(instr->result()), operand);
3061 } else {
3062 __ fld_d(operand);
3063 HandleX87FPReturnValue(instr);
3064 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003065 } else {
3066 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003067 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003068 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003069 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003070 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003071 case EXTERNAL_PIXEL_ELEMENTS:
3072 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003073 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003074 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003075 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003076 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003077 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003078 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003079 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003080 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003081 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003082 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003083 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003084 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003085 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003086 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3087 __ test(result, Operand(result));
3088 DeoptimizeIf(negative, instr->environment());
3089 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003090 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003091 case EXTERNAL_FLOAT_ELEMENTS:
3092 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003093 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003094 case FAST_ELEMENTS:
3095 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003096 case FAST_HOLEY_SMI_ELEMENTS:
3097 case FAST_HOLEY_ELEMENTS:
3098 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003099 case DICTIONARY_ELEMENTS:
3100 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003101 UNREACHABLE();
3102 break;
3103 }
3104 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003105}
3106
3107
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003108void LCodeGen::HandleX87FPReturnValue(LInstruction* instr) {
3109 if (IsX87TopOfStack(instr->result())) {
3110 // Return value is already on stack. If the value has no uses, then
3111 // pop it off the FP stack. Otherwise, make sure that there are enough
3112 // copies of the value on the stack to feed all of the usages, e.g.
3113 // when the following instruction uses the return value in multiple
3114 // inputs.
3115 int count = instr->hydrogen_value()->UseCount();
3116 if (count == 0) {
3117 __ fstp(0);
3118 } else {
3119 count--;
3120 ASSERT(count <= 7);
3121 while (count-- > 0) {
3122 __ fld(0);
3123 }
3124 }
3125 } else {
3126 __ fstp_d(ToOperand(instr->result()));
3127 }
3128}
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00003129
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003130
3131void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003132 if (instr->hydrogen()->RequiresHoleCheck()) {
3133 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3134 sizeof(kHoleNanLower32);
3135 Operand hole_check_operand = BuildFastArrayOperand(
3136 instr->elements(), instr->key(),
3137 instr->hydrogen()->key()->representation(),
3138 FAST_DOUBLE_ELEMENTS,
3139 offset,
3140 instr->additional_index());
3141 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3142 DeoptimizeIf(equal, instr->environment());
3143 }
3144
3145 Operand double_load_operand = BuildFastArrayOperand(
3146 instr->elements(),
3147 instr->key(),
3148 instr->hydrogen()->key()->representation(),
3149 FAST_DOUBLE_ELEMENTS,
3150 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3151 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003152 if (CpuFeatures::IsSupported(SSE2)) {
3153 CpuFeatures::Scope scope(SSE2);
3154 XMMRegister result = ToDoubleRegister(instr->result());
3155 __ movdbl(result, double_load_operand);
3156 } else {
3157 __ fld_d(double_load_operand);
3158 HandleX87FPReturnValue(instr);
3159 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003160}
3161
3162
3163void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3164 Register result = ToRegister(instr->result());
3165
3166 // Load the result.
3167 __ mov(result,
3168 BuildFastArrayOperand(instr->elements(),
3169 instr->key(),
3170 instr->hydrogen()->key()->representation(),
3171 FAST_ELEMENTS,
3172 FixedArray::kHeaderSize - kHeapObjectTag,
3173 instr->additional_index()));
3174
3175 // Check for the hole value.
3176 if (instr->hydrogen()->RequiresHoleCheck()) {
3177 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3178 __ test(result, Immediate(kSmiTagMask));
3179 DeoptimizeIf(not_equal, instr->environment());
3180 } else {
3181 __ cmp(result, factory()->the_hole_value());
3182 DeoptimizeIf(equal, instr->environment());
3183 }
3184 }
3185}
3186
3187
3188void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3189 if (instr->is_external()) {
3190 DoLoadKeyedExternalArray(instr);
3191 } else if (instr->hydrogen()->representation().IsDouble()) {
3192 DoLoadKeyedFixedDoubleArray(instr);
3193 } else {
3194 DoLoadKeyedFixedArray(instr);
3195 }
3196}
3197
3198
3199Operand LCodeGen::BuildFastArrayOperand(
3200 LOperand* elements_pointer,
3201 LOperand* key,
3202 Representation key_representation,
3203 ElementsKind elements_kind,
3204 uint32_t offset,
3205 uint32_t additional_index) {
3206 Register elements_pointer_reg = ToRegister(elements_pointer);
3207 int shift_size = ElementsKindToShiftSize(elements_kind);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003208 if (key->IsConstantOperand()) {
3209 int constant_value = ToInteger32(LConstantOperand::cast(key));
3210 if (constant_value & 0xF0000000) {
3211 Abort("array index constant value too big");
3212 }
3213 return Operand(elements_pointer_reg,
3214 ((constant_value + additional_index) << shift_size)
3215 + offset);
3216 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003217 // Take the tag bit into account while computing the shift size.
3218 if (key_representation.IsTagged() && (shift_size >= 1)) {
3219 shift_size -= kSmiTagSize;
3220 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003221 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3222 return Operand(elements_pointer_reg,
3223 ToRegister(key),
3224 scale_factor,
3225 offset + (additional_index << shift_size));
3226 }
3227}
3228
3229
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003230void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003231 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003232 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003233 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003234
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003235 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003236 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003237}
3238
3239
3240void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3241 Register result = ToRegister(instr->result());
3242
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003243 if (instr->hydrogen()->from_inlined()) {
3244 __ lea(result, Operand(esp, -2 * kPointerSize));
3245 } else {
3246 // Check for arguments adapter frame.
3247 Label done, adapted;
3248 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3249 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3250 __ cmp(Operand(result),
3251 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3252 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003253
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003254 // No arguments adaptor frame.
3255 __ mov(result, Operand(ebp));
3256 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003257
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003258 // Arguments adaptor frame present.
3259 __ bind(&adapted);
3260 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003261
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003262 // Result is the frame pointer for the frame if not adapted and for the real
3263 // frame below the adaptor frame if adapted.
3264 __ bind(&done);
3265 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003266}
3267
3268
3269void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003270 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003271 Register result = ToRegister(instr->result());
3272
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003273 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003274
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003275 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003276 __ cmp(ebp, elem);
3277 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003278 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003279
3280 // Arguments adaptor frame present. Get argument length from there.
3281 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3282 __ mov(result, Operand(result,
3283 ArgumentsAdaptorFrameConstants::kLengthOffset));
3284 __ SmiUntag(result);
3285
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003286 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003287 __ bind(&done);
3288}
3289
3290
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003291void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003292 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003293 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003294 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003295
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003296 // If the receiver is null or undefined, we have to pass the global
3297 // object as a receiver to normal functions. Values have to be
3298 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003299 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003300
3301 // Do not transform the receiver to object for strict mode
3302 // functions.
3303 __ mov(scratch,
3304 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3305 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3306 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003307 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003308
3309 // Do not transform the receiver to object for builtins.
3310 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3311 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003312 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003313
3314 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003315 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003316 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003317 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003318 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003319
3320 // The receiver should be a JS object.
3321 __ test(receiver, Immediate(kSmiTagMask));
3322 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003323 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003324 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003325 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003326
3327 __ bind(&global_object);
3328 // TODO(kmillikin): We have a hydrogen value for the global object. See
3329 // if it's better to use it than to explicitly fetch it from the context
3330 // here.
3331 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003332 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003333 __ mov(receiver,
3334 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003335 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003336}
3337
3338
3339void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3340 Register receiver = ToRegister(instr->receiver());
3341 Register function = ToRegister(instr->function());
3342 Register length = ToRegister(instr->length());
3343 Register elements = ToRegister(instr->elements());
3344 ASSERT(receiver.is(eax)); // Used for parameter count.
3345 ASSERT(function.is(edi)); // Required by InvokeFunction.
3346 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003347
3348 // Copy the arguments to this function possibly from the
3349 // adaptor frame below it.
3350 const uint32_t kArgumentsLimit = 1 * KB;
3351 __ cmp(length, kArgumentsLimit);
3352 DeoptimizeIf(above, instr->environment());
3353
3354 __ push(receiver);
3355 __ mov(receiver, length);
3356
3357 // Loop through the arguments pushing them onto the execution
3358 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003359 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003360 // length is a small non-negative integer, due to the test above.
3361 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003362 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003363 __ bind(&loop);
3364 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3365 __ dec(length);
3366 __ j(not_zero, &loop);
3367
3368 // Invoke the function.
3369 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003370 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003371 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003372 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003373 SafepointGenerator safepoint_generator(
3374 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003375 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003376 __ InvokeFunction(function, actual, CALL_FUNCTION,
3377 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003378}
3379
3380
3381void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003382 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003383 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003384}
3385
3386
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003387void LCodeGen::DoDrop(LDrop* instr) {
3388 __ Drop(instr->count());
3389}
3390
3391
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003392void LCodeGen::DoThisFunction(LThisFunction* instr) {
3393 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003394 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003395}
3396
3397
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003398void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003399 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003400 if (info()->IsOptimizing()) {
3401 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3402 } else {
3403 // If there is no frame, the context must be in esi.
3404 ASSERT(result.is(esi));
3405 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003406}
3407
3408
3409void LCodeGen::DoOuterContext(LOuterContext* instr) {
3410 Register context = ToRegister(instr->context());
3411 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003412 __ mov(result,
3413 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003414}
3415
3416
yangguo@chromium.org56454712012-02-16 15:33:53 +00003417void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003418 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003419 __ push(esi); // The context is the first argument.
3420 __ push(Immediate(instr->hydrogen()->pairs()));
3421 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3422 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3423}
3424
3425
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003426void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3427 Register context = ToRegister(instr->context());
3428 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003429 __ mov(result,
3430 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003431}
3432
3433
3434void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003435 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003436 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003437 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003438}
3439
3440
3441void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
3442 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003443 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003444 CallKind call_kind,
3445 EDIState edi_state) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003446 bool can_invoke_directly = !function->NeedsArgumentsAdaption() ||
3447 function->shared()->formal_parameter_count() == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003448
3449 LPointerMap* pointers = instr->pointer_map();
3450 RecordPosition(pointers->position());
3451
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003452 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003453 if (edi_state == EDI_UNINITIALIZED) {
3454 __ LoadHeapObject(edi, function);
3455 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003456
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003457 // Change context.
3458 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003459
3460 // Set eax to arguments count if adaption is not needed. Assumes that eax
3461 // is available to write to at this point.
3462 if (!function->NeedsArgumentsAdaption()) {
3463 __ mov(eax, arity);
3464 }
3465
3466 // Invoke function directly.
3467 __ SetCallKind(ecx, call_kind);
3468 if (*function == *info()->closure()) {
3469 __ CallSelf();
3470 } else {
3471 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3472 }
3473 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3474 } else {
3475 // We need to adapt arguments.
3476 SafepointGenerator generator(
3477 this, pointers, Safepoint::kLazyDeopt);
3478 ParameterCount count(arity);
3479 __ InvokeFunction(function, count, CALL_FUNCTION, generator, call_kind);
3480 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003481}
3482
3483
3484void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3485 ASSERT(ToRegister(instr->result()).is(eax));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003486 CallKnownFunction(instr->function(),
3487 instr->arity(),
3488 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003489 CALL_AS_METHOD,
3490 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003491}
3492
3493
3494void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003495 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003496 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003497 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003498 DeoptimizeIf(not_equal, instr->environment());
3499
3500 Label done;
3501 Register tmp = input_reg.is(eax) ? ecx : eax;
3502 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3503
3504 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003505 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003506
3507 Label negative;
3508 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003509 // Check the sign of the argument. If the argument is positive, just
3510 // return it. We do not need to patch the stack since |input| and
3511 // |result| are the same register and |input| will be restored
3512 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003513 __ test(tmp, Immediate(HeapNumber::kSignMask));
3514 __ j(not_zero, &negative);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003515 __ jmp(&done);
3516
3517 __ bind(&negative);
3518
3519 Label allocated, slow;
3520 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
3521 __ jmp(&allocated);
3522
3523 // Slow case: Call the runtime system to do the number allocation.
3524 __ bind(&slow);
3525
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003526 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3527 instr, instr->context());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003528
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003529 // Set the pointer to the new heap number in tmp.
3530 if (!tmp.is(eax)) __ mov(tmp, eax);
3531
3532 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003533 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003534
3535 __ bind(&allocated);
3536 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3537 __ and_(tmp2, ~HeapNumber::kSignMask);
3538 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3539 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3540 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003541 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003542
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003543 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003544}
3545
3546
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003547void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003548 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003549 __ test(input_reg, Operand(input_reg));
3550 Label is_positive;
3551 __ j(not_sign, &is_positive);
3552 __ neg(input_reg);
3553 __ test(input_reg, Operand(input_reg));
3554 DeoptimizeIf(negative, instr->environment());
3555 __ bind(&is_positive);
3556}
3557
3558
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003559void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
3560 // Class for deferred case.
3561 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3562 public:
3563 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3564 LUnaryMathOperation* instr)
3565 : LDeferredCode(codegen), instr_(instr) { }
3566 virtual void Generate() {
3567 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3568 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003569 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003570 private:
3571 LUnaryMathOperation* instr_;
3572 };
3573
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003574 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003575 Representation r = instr->hydrogen()->value()->representation();
3576
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003577 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003578 if (r.IsDouble()) {
3579 XMMRegister scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003580 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003581 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003582 __ subsd(scratch, input_reg);
3583 __ pand(input_reg, scratch);
3584 } else if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003585 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003586 } else { // Tagged case.
3587 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003588 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003589 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003590 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003591 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003592 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003593 __ bind(deferred->exit());
3594 }
3595}
3596
3597
3598void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003599 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003600 XMMRegister xmm_scratch = xmm0;
3601 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003602 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003604 if (CpuFeatures::IsSupported(SSE4_1)) {
3605 CpuFeatures::Scope scope(SSE4_1);
3606 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3607 // Deoptimize on negative zero.
3608 Label non_zero;
3609 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3610 __ ucomisd(input_reg, xmm_scratch);
3611 __ j(not_equal, &non_zero, Label::kNear);
3612 __ movmskpd(output_reg, input_reg);
3613 __ test(output_reg, Immediate(1));
3614 DeoptimizeIf(not_zero, instr->environment());
3615 __ bind(&non_zero);
3616 }
3617 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3618 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3619 // Overflow is signalled with minint.
3620 __ cmp(output_reg, 0x80000000u);
3621 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003623 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003624 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003625 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3626 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003627 DeoptimizeIf(parity_even, instr->environment());
3628 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003629
3630 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3631 // Check for negative zero.
3632 Label positive_sign;
3633 __ j(above, &positive_sign, Label::kNear);
3634 __ movmskpd(output_reg, input_reg);
3635 __ test(output_reg, Immediate(1));
3636 DeoptimizeIf(not_zero, instr->environment());
3637 __ Set(output_reg, Immediate(0));
3638 __ jmp(&done, Label::kNear);
3639 __ bind(&positive_sign);
3640 }
3641
3642 // Use truncating instruction (OK because input is positive).
3643 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003644 // Overflow is signalled with minint.
3645 __ cmp(output_reg, 0x80000000u);
3646 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003647 __ jmp(&done, Label::kNear);
3648
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003649 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003650 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003651 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003652 __ cvttsd2si(output_reg, Operand(input_reg));
3653 __ cvtsi2sd(xmm_scratch, output_reg);
3654 __ ucomisd(input_reg, xmm_scratch);
3655 __ j(equal, &done, Label::kNear);
3656 __ sub(output_reg, Immediate(1));
3657 DeoptimizeIf(overflow, instr->environment());
3658
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003659 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003660 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003661}
3662
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003663void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003664 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003665 XMMRegister xmm_scratch = xmm0;
3666 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003667 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003668
danno@chromium.org160a7b02011-04-18 15:51:38 +00003669 Label below_half, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003670 // xmm_scratch = 0.5
3671 ExternalReference one_half = ExternalReference::address_of_one_half();
3672 __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003673 __ ucomisd(xmm_scratch, input_reg);
3674 __ j(above, &below_half);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003675 // xmm_scratch = input + 0.5
3676 __ addsd(xmm_scratch, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003678 // Compute Math.floor(value + 0.5).
3679 // Use truncating instruction (OK because input is positive).
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003680 __ cvttsd2si(output_reg, Operand(xmm_scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003681
3682 // Overflow is signalled with minint.
3683 __ cmp(output_reg, 0x80000000u);
3684 DeoptimizeIf(equal, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003685 __ jmp(&done);
3686
3687 __ bind(&below_half);
3688
3689 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3690 // we can ignore the difference between a result of -0 and +0.
3691 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3692 // If the sign is positive, we return +0.
3693 __ movmskpd(output_reg, input_reg);
3694 __ test(output_reg, Immediate(1));
3695 DeoptimizeIf(not_zero, instr->environment());
3696 } else {
3697 // If the input is >= -0.5, we return +0.
3698 __ mov(output_reg, Immediate(0xBF000000));
3699 __ movd(xmm_scratch, Operand(output_reg));
3700 __ cvtss2sd(xmm_scratch, xmm_scratch);
3701 __ ucomisd(input_reg, xmm_scratch);
3702 DeoptimizeIf(below, instr->environment());
3703 }
3704 __ Set(output_reg, Immediate(0));
3705 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706}
3707
3708
3709void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003710 CpuFeatures::Scope scope(SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003711 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003712 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3713 __ sqrtsd(input_reg, input_reg);
3714}
3715
3716
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003717void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003718 CpuFeatures::Scope scope(SSE2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003719 XMMRegister xmm_scratch = xmm0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003720 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003721 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003722 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003723
3724 // Note that according to ECMA-262 15.8.2.13:
3725 // Math.pow(-Infinity, 0.5) == Infinity
3726 // Math.sqrt(-Infinity) == NaN
3727 Label done, sqrt;
3728 // Check base for -Infinity. According to IEEE-754, single-precision
3729 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
3730 __ mov(scratch, 0xFF800000);
3731 __ movd(xmm_scratch, scratch);
3732 __ cvtss2sd(xmm_scratch, xmm_scratch);
3733 __ ucomisd(input_reg, xmm_scratch);
3734 // Comparing -Infinity with NaN results in "unordered", which sets the
3735 // zero flag as if both were equal. However, it also sets the carry flag.
3736 __ j(not_equal, &sqrt, Label::kNear);
3737 __ j(carry, &sqrt, Label::kNear);
3738 // If input is -Infinity, return Infinity.
3739 __ xorps(input_reg, input_reg);
3740 __ subsd(input_reg, xmm_scratch);
3741 __ jmp(&done, Label::kNear);
3742
3743 // Square root.
3744 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003745 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003746 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003747 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003748 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003749}
3750
3751
3752void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003753 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003754 // Having marked this as a call, we can use any registers.
3755 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003756 ASSERT(!instr->right()->IsDoubleRegister() ||
3757 ToDoubleRegister(instr->right()).is(xmm1));
3758 ASSERT(!instr->right()->IsRegister() ||
3759 ToRegister(instr->right()).is(eax));
3760 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003761 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003762
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003763 if (exponent_type.IsTagged()) {
3764 Label no_deopt;
3765 __ JumpIfSmi(eax, &no_deopt);
3766 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003767 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003768 __ bind(&no_deopt);
3769 MathPowStub stub(MathPowStub::TAGGED);
3770 __ CallStub(&stub);
3771 } else if (exponent_type.IsInteger32()) {
3772 MathPowStub stub(MathPowStub::INTEGER);
3773 __ CallStub(&stub);
3774 } else {
3775 ASSERT(exponent_type.IsDouble());
3776 MathPowStub stub(MathPowStub::DOUBLE);
3777 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003778 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003779}
3780
3781
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003782void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003783 class DeferredDoRandom: public LDeferredCode {
3784 public:
3785 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3786 : LDeferredCode(codegen), instr_(instr) { }
3787 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3788 virtual LInstruction* instr() { return instr_; }
3789 private:
3790 LRandom* instr_;
3791 };
3792
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003793 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003794
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003795 CpuFeatures::Scope scope(SSE2);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003796 // Having marked this instruction as a call we can use any
3797 // registers.
3798 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003799 ASSERT(ToRegister(instr->global_object()).is(eax));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003800 // Assert that the register size is indeed the size of each seed.
3801 static const int kSeedSize = sizeof(uint32_t);
3802 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003803
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003804 __ mov(eax, FieldOperand(eax, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003805 static const int kRandomSeedOffset =
3806 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3807 __ mov(ebx, FieldOperand(eax, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003808 // ebx: FixedArray of the native context's random seeds
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003809
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003810 // Load state[0].
3811 __ mov(ecx, FieldOperand(ebx, ByteArray::kHeaderSize));
3812 // If state[0] == 0, call runtime to initialize seeds.
3813 __ test(ecx, ecx);
3814 __ j(zero, deferred->entry());
3815 // Load state[1].
3816 __ mov(eax, FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize));
3817 // ecx: state[0]
3818 // eax: state[1]
3819
3820 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3821 __ movzx_w(edx, ecx);
3822 __ imul(edx, edx, 18273);
3823 __ shr(ecx, 16);
3824 __ add(ecx, edx);
3825 // Save state[0].
3826 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize), ecx);
3827
3828 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3829 __ movzx_w(edx, eax);
3830 __ imul(edx, edx, 36969);
3831 __ shr(eax, 16);
3832 __ add(eax, edx);
3833 // Save state[1].
3834 __ mov(FieldOperand(ebx, ByteArray::kHeaderSize + kSeedSize), eax);
3835
3836 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3837 __ shl(ecx, 14);
3838 __ and_(eax, Immediate(0x3FFFF));
3839 __ add(eax, ecx);
3840
3841 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003842 // Convert 32 random bits in eax to 0.(32 random bits) in a double
3843 // by computing:
3844 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
3845 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
3846 __ movd(xmm2, ebx);
3847 __ movd(xmm1, eax);
3848 __ cvtss2sd(xmm2, xmm2);
3849 __ xorps(xmm1, xmm2);
3850 __ subsd(xmm1, xmm2);
3851}
3852
3853
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003854void LCodeGen::DoDeferredRandom(LRandom* instr) {
3855 __ PrepareCallCFunction(1, ebx);
3856 __ mov(Operand(esp, 0), eax);
3857 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3858 // Return value is in eax.
3859}
3860
3861
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003862void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003863 CpuFeatures::Scope scope(SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003864 ASSERT(instr->value()->Equals(instr->result()));
3865 XMMRegister input_reg = ToDoubleRegister(instr->value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003866 Label positive, done, zero;
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003867 __ xorps(xmm0, xmm0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003868 __ ucomisd(input_reg, xmm0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003869 __ j(above, &positive, Label::kNear);
3870 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003871 ExternalReference nan =
3872 ExternalReference::address_of_canonical_non_hole_nan();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003873 __ movdbl(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003874 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003875 __ bind(&zero);
3876 __ push(Immediate(0xFFF00000));
3877 __ push(Immediate(0));
3878 __ movdbl(input_reg, Operand(esp, 0));
3879 __ add(Operand(esp), Immediate(kDoubleSize));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003880 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003881 __ bind(&positive);
3882 __ fldln2();
3883 __ sub(Operand(esp), Immediate(kDoubleSize));
3884 __ movdbl(Operand(esp, 0), input_reg);
3885 __ fld_d(Operand(esp, 0));
3886 __ fyl2x();
3887 __ fstp_d(Operand(esp, 0));
3888 __ movdbl(input_reg, Operand(esp, 0));
3889 __ add(Operand(esp), Immediate(kDoubleSize));
3890 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003891}
3892
3893
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003894void LCodeGen::DoMathExp(LMathExp* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003895 CpuFeatures::Scope scope(SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003896 XMMRegister input = ToDoubleRegister(instr->value());
3897 XMMRegister result = ToDoubleRegister(instr->result());
3898 Register temp1 = ToRegister(instr->temp1());
3899 Register temp2 = ToRegister(instr->temp2());
3900
3901 MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
3902}
3903
3904
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003905void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
3906 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3907 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3908 TranscendentalCacheStub::UNTAGGED);
3909 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3910}
3911
3912
whesse@chromium.org023421e2010-12-21 12:19:12 +00003913void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3914 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3915 TranscendentalCacheStub stub(TranscendentalCache::COS,
3916 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003917 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00003918}
3919
3920
3921void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3922 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3923 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3924 TranscendentalCacheStub::UNTAGGED);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003925 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003926}
3927
3928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003929void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
3930 switch (instr->op()) {
3931 case kMathAbs:
3932 DoMathAbs(instr);
3933 break;
3934 case kMathFloor:
3935 DoMathFloor(instr);
3936 break;
3937 case kMathRound:
3938 DoMathRound(instr);
3939 break;
3940 case kMathSqrt:
3941 DoMathSqrt(instr);
3942 break;
whesse@chromium.org023421e2010-12-21 12:19:12 +00003943 case kMathCos:
3944 DoMathCos(instr);
3945 break;
3946 case kMathSin:
3947 DoMathSin(instr);
3948 break;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003949 case kMathTan:
3950 DoMathTan(instr);
3951 break;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003952 case kMathLog:
3953 DoMathLog(instr);
3954 break;
3955
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003956 default:
3957 UNREACHABLE();
3958 }
3959}
3960
3961
danno@chromium.org160a7b02011-04-18 15:51:38 +00003962void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3963 ASSERT(ToRegister(instr->context()).is(esi));
3964 ASSERT(ToRegister(instr->function()).is(edi));
3965 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003966
3967 if (instr->known_function().is_null()) {
3968 LPointerMap* pointers = instr->pointer_map();
3969 RecordPosition(pointers->position());
3970 SafepointGenerator generator(
3971 this, pointers, Safepoint::kLazyDeopt);
3972 ParameterCount count(instr->arity());
3973 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3974 } else {
3975 CallKnownFunction(instr->known_function(),
3976 instr->arity(),
3977 instr,
3978 CALL_AS_METHOD,
3979 EDI_CONTAINS_TARGET);
3980 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003981}
3982
3983
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003984void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003985 ASSERT(ToRegister(instr->context()).is(esi));
3986 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003987 ASSERT(ToRegister(instr->result()).is(eax));
3988
3989 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003990 Handle<Code> ic =
3991 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003992 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003993}
3994
3995
3996void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003997 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003998 ASSERT(ToRegister(instr->result()).is(eax));
3999
4000 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004001 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4002 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004003 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004004 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004005 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004006}
4007
4008
4009void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004010 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004011 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004012 ASSERT(ToRegister(instr->result()).is(eax));
4013
4014 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004016 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004017}
4018
4019
4020void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004021 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004022 ASSERT(ToRegister(instr->result()).is(eax));
4023
4024 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004025 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4026 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004027 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004028 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004029 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004030}
4031
4032
4033void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4034 ASSERT(ToRegister(instr->result()).is(eax));
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004035 CallKnownFunction(instr->target(),
4036 instr->arity(),
4037 instr,
4038 CALL_AS_FUNCTION,
4039 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004040}
4041
4042
4043void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004044 ASSERT(ToRegister(instr->context()).is(esi));
4045 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004046 ASSERT(ToRegister(instr->result()).is(eax));
4047
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004048 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004049 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004050 CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004051}
4052
4053
4054void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004055 CallRuntime(instr->function(), instr->arity(), instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004056}
4057
4058
4059void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
4060 Register object = ToRegister(instr->object());
4061 Register value = ToRegister(instr->value());
4062 int offset = instr->offset();
4063
4064 if (!instr->transition().is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004065 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
4066 __ mov(FieldOperand(object, HeapObject::kMapOffset), instr->transition());
4067 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004068 Register temp = ToRegister(instr->temp());
4069 Register temp_map = ToRegister(instr->temp_map());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004070 __ mov(temp_map, instr->transition());
4071 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4072 // Update the write barrier for the map field.
4073 __ RecordWriteField(object,
4074 HeapObject::kMapOffset,
4075 temp_map,
4076 temp,
4077 kSaveFPRegs,
4078 OMIT_REMEMBERED_SET,
4079 OMIT_SMI_CHECK);
4080 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004081 }
4082
4083 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004084 HType type = instr->hydrogen()->value()->type();
4085 SmiCheck check_needed =
4086 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004087 if (instr->is_in_object()) {
4088 __ mov(FieldOperand(object, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004089 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004090 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004091 // Update the write barrier for the object for in-object properties.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004092 __ RecordWriteField(object,
4093 offset,
4094 value,
4095 temp,
4096 kSaveFPRegs,
4097 EMIT_REMEMBERED_SET,
4098 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004099 }
4100 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004101 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004102 __ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset));
4103 __ mov(FieldOperand(temp, offset), value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004104 if (instr->hydrogen()->NeedsWriteBarrier()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004105 // Update the write barrier for the properties array.
4106 // object is used as a scratch register.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004107 __ RecordWriteField(temp,
4108 offset,
4109 value,
4110 object,
4111 kSaveFPRegs,
4112 EMIT_REMEMBERED_SET,
4113 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004114 }
4115 }
4116}
4117
4118
4119void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004120 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004121 ASSERT(ToRegister(instr->object()).is(edx));
4122 ASSERT(ToRegister(instr->value()).is(eax));
4123
4124 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004125 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004126 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4127 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004128 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004129}
4130
4131
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004132void LCodeGen::DeoptIfTaggedButNotSmi(LEnvironment* environment,
4133 HValue* value,
4134 LOperand* operand) {
4135 if (value->representation().IsTagged() && !value->type().IsSmi()) {
4136 if (operand->IsRegister()) {
4137 __ test(ToRegister(operand), Immediate(kSmiTagMask));
4138 } else {
4139 __ test(ToOperand(operand), Immediate(kSmiTagMask));
4140 }
4141 DeoptimizeIf(not_zero, environment);
4142 }
4143}
4144
4145
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004146void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004147 DeoptIfTaggedButNotSmi(instr->environment(),
4148 instr->hydrogen()->length(),
4149 instr->length());
4150 DeoptIfTaggedButNotSmi(instr->environment(),
4151 instr->hydrogen()->index(),
4152 instr->index());
danno@chromium.orgb6451162011-08-17 14:33:23 +00004153 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004154 int constant_index =
4155 ToInteger32(LConstantOperand::cast(instr->index()));
4156 if (instr->hydrogen()->length()->representation().IsTagged()) {
4157 __ cmp(ToOperand(instr->length()),
4158 Immediate(Smi::FromInt(constant_index)));
4159 } else {
4160 __ cmp(ToOperand(instr->length()), Immediate(constant_index));
4161 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004162 DeoptimizeIf(below_equal, instr->environment());
4163 } else {
4164 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
4165 DeoptimizeIf(above_equal, instr->environment());
4166 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004167}
4168
4169
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004170void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004171 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004172 LOperand* key = instr->key();
4173 if (!key->IsConstantOperand() &&
4174 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4175 elements_kind)) {
4176 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004177 }
4178 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004179 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004180 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004181 instr->hydrogen()->key()->representation(),
4182 elements_kind,
4183 0,
4184 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004185 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004186 CpuFeatures::Scope scope(SSE2);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004187 __ cvtsd2ss(xmm0, ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004188 __ movss(operand, xmm0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004189 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004190 CpuFeatures::Scope scope(SSE2);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004191 __ movdbl(operand, ToDoubleRegister(instr->value()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004192 } else {
4193 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004194 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004195 case EXTERNAL_PIXEL_ELEMENTS:
4196 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4197 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004198 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004199 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004200 case EXTERNAL_SHORT_ELEMENTS:
4201 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004202 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004203 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004204 case EXTERNAL_INT_ELEMENTS:
4205 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004206 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004207 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004208 case EXTERNAL_FLOAT_ELEMENTS:
4209 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004210 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004211 case FAST_ELEMENTS:
4212 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004213 case FAST_HOLEY_SMI_ELEMENTS:
4214 case FAST_HOLEY_ELEMENTS:
4215 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004216 case DICTIONARY_ELEMENTS:
4217 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004218 UNREACHABLE();
4219 break;
4220 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004221 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004222}
4223
4224
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004225void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004226 CpuFeatures::Scope scope(SSE2);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004227 XMMRegister value = ToDoubleRegister(instr->value());
4228
4229 if (instr->NeedsCanonicalization()) {
4230 Label have_value;
4231
4232 __ ucomisd(value, value);
4233 __ j(parity_odd, &have_value); // NaN.
4234
4235 ExternalReference canonical_nan_reference =
4236 ExternalReference::address_of_canonical_non_hole_nan();
4237 __ movdbl(value, Operand::StaticVariable(canonical_nan_reference));
4238 __ bind(&have_value);
4239 }
4240
4241 Operand double_store_operand = BuildFastArrayOperand(
4242 instr->elements(),
4243 instr->key(),
4244 instr->hydrogen()->key()->representation(),
4245 FAST_DOUBLE_ELEMENTS,
4246 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4247 instr->additional_index());
4248 __ movdbl(double_store_operand, value);
4249}
4250
4251
4252void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004253 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004254 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004255 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4256
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004257 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004258 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004259 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004260 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004261 FAST_ELEMENTS,
4262 FixedArray::kHeaderSize - kHeapObjectTag,
4263 instr->additional_index());
4264 __ mov(operand, value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004265
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004266 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004267 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004268 HType type = instr->hydrogen()->value()->type();
4269 SmiCheck check_needed =
4270 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004271 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004272 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004273 __ RecordWrite(elements,
4274 key,
4275 value,
4276 kSaveFPRegs,
4277 EMIT_REMEMBERED_SET,
4278 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004279 }
4280}
4281
4282
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004283void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4284 // By cases...external, fast-double, fast
4285 if (instr->is_external()) {
4286 DoStoreKeyedExternalArray(instr);
4287 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4288 DoStoreKeyedFixedDoubleArray(instr);
4289 } else {
4290 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004291 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004292}
4293
4294
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004295void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004296 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004297 ASSERT(ToRegister(instr->object()).is(edx));
4298 ASSERT(ToRegister(instr->key()).is(ecx));
4299 ASSERT(ToRegister(instr->value()).is(eax));
4300
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004301 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004302 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4303 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004304 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004305}
4306
4307
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004308void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4309 Register object_reg = ToRegister(instr->object());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004310 Register new_map_reg = ToRegister(instr->new_map_temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004311
4312 Handle<Map> from_map = instr->original_map();
4313 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004314 ElementsKind from_kind = instr->from_kind();
4315 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004316
4317 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004318 bool is_simple_map_transition =
4319 IsSimpleMapChangeTransition(from_kind, to_kind);
4320 Label::Distance branch_distance =
4321 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004322 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004323 __ j(not_equal, &not_applicable, branch_distance);
4324 if (is_simple_map_transition) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004325 Register object_reg = ToRegister(instr->object());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004326 Handle<Map> map = instr->hydrogen()->transitioned_map();
4327 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
4328 Immediate(map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004329 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004330 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004331 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004332 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004333 kDontSaveFPRegs);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004334 } else if (IsFastSmiElementsKind(from_kind) &&
4335 IsFastDoubleElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004336 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004337 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004338 ASSERT(fixed_object_reg.is(edx));
4339 ASSERT(new_map_reg.is(ebx));
4340 __ mov(fixed_object_reg, object_reg);
4341 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4342 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004343 } else if (IsFastDoubleElementsKind(from_kind) &&
4344 IsFastObjectElementsKind(to_kind)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004345 __ mov(new_map_reg, to_map);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004346 Register fixed_object_reg = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004347 ASSERT(fixed_object_reg.is(edx));
4348 ASSERT(new_map_reg.is(ebx));
4349 __ mov(fixed_object_reg, object_reg);
4350 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4351 RelocInfo::CODE_TARGET, instr);
4352 } else {
4353 UNREACHABLE();
4354 }
4355 __ bind(&not_applicable);
4356}
4357
4358
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004359void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4360 class DeferredStringCharCodeAt: public LDeferredCode {
4361 public:
4362 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4363 : LDeferredCode(codegen), instr_(instr) { }
4364 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004365 virtual LInstruction* instr() { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004366 private:
4367 LStringCharCodeAt* instr_;
4368 };
4369
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004370 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004371 new(zone()) DeferredStringCharCodeAt(this, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004372
erikcorry0ad885c2011-11-21 13:51:57 +00004373 StringCharLoadGenerator::Generate(masm(),
4374 factory(),
4375 ToRegister(instr->string()),
4376 ToRegister(instr->index()),
4377 ToRegister(instr->result()),
4378 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004379 __ bind(deferred->exit());
4380}
4381
4382
4383void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4384 Register string = ToRegister(instr->string());
4385 Register result = ToRegister(instr->result());
4386
4387 // TODO(3095996): Get rid of this. For now, we need to make the
4388 // result register contain a valid pointer because it is already
4389 // contained in the register pointer map.
4390 __ Set(result, Immediate(0));
4391
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004392 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004393 __ push(string);
4394 // Push the index as a smi. This is safe because of the checks in
4395 // DoStringCharCodeAt above.
4396 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4397 if (instr->index()->IsConstantOperand()) {
4398 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4399 __ push(Immediate(Smi::FromInt(const_index)));
4400 } else {
4401 Register index = ToRegister(instr->index());
4402 __ SmiTag(index);
4403 __ push(index);
4404 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004405 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4406 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004407 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004408 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004409 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004410}
4411
4412
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004413void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4414 class DeferredStringCharFromCode: public LDeferredCode {
4415 public:
4416 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4417 : LDeferredCode(codegen), instr_(instr) { }
4418 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004419 virtual LInstruction* instr() { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004420 private:
4421 LStringCharFromCode* instr_;
4422 };
4423
4424 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004425 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004426
4427 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4428 Register char_code = ToRegister(instr->char_code());
4429 Register result = ToRegister(instr->result());
4430 ASSERT(!char_code.is(result));
4431
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004432 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004433 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004434 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004435 __ mov(result, FieldOperand(result,
4436 char_code, times_pointer_size,
4437 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004438 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004439 __ j(equal, deferred->entry());
4440 __ bind(deferred->exit());
4441}
4442
4443
4444void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4445 Register char_code = ToRegister(instr->char_code());
4446 Register result = ToRegister(instr->result());
4447
4448 // TODO(3095996): Get rid of this. For now, we need to make the
4449 // result register contain a valid pointer because it is already
4450 // contained in the register pointer map.
4451 __ Set(result, Immediate(0));
4452
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004453 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004454 __ SmiTag(char_code);
4455 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004456 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004457 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004458}
4459
4460
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004461void LCodeGen::DoStringLength(LStringLength* instr) {
4462 Register string = ToRegister(instr->string());
4463 Register result = ToRegister(instr->result());
4464 __ mov(result, FieldOperand(string, String::kLengthOffset));
4465}
4466
4467
danno@chromium.org160a7b02011-04-18 15:51:38 +00004468void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004469 EmitPushTaggedOperand(instr->left());
4470 EmitPushTaggedOperand(instr->right());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004471 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004472 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004473}
4474
4475
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004476void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004477 if (CpuFeatures::IsSupported(SSE2)) {
4478 CpuFeatures::Scope scope(SSE2);
4479 LOperand* input = instr->value();
4480 ASSERT(input->IsRegister() || input->IsStackSlot());
4481 LOperand* output = instr->result();
4482 ASSERT(output->IsDoubleRegister());
4483 __ cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
4484 } else {
4485 UNREACHABLE();
4486 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004487}
4488
4489
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004490void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004491 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004492 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004493 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004494 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004495
4496 __ LoadUint32(ToDoubleRegister(output),
4497 ToRegister(input),
4498 ToDoubleRegister(temp));
4499}
4500
4501
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004502void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4503 class DeferredNumberTagI: public LDeferredCode {
4504 public:
4505 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4506 : LDeferredCode(codegen), instr_(instr) { }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004507 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004508 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004509 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004510 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004511 private:
4512 LNumberTagI* instr_;
4513 };
4514
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004515 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004516 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4517 Register reg = ToRegister(input);
4518
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004519 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004520 __ SmiTag(reg);
4521 __ j(overflow, deferred->entry());
4522 __ bind(deferred->exit());
4523}
4524
4525
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004526void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4527 class DeferredNumberTagU: public LDeferredCode {
4528 public:
4529 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4530 : LDeferredCode(codegen), instr_(instr) { }
4531 virtual void Generate() {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004532 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004533 }
4534 virtual LInstruction* instr() { return instr_; }
4535 private:
4536 LNumberTagU* instr_;
4537 };
4538
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004539 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004540 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4541 Register reg = ToRegister(input);
4542
4543 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4544 __ cmp(reg, Immediate(Smi::kMaxValue));
4545 __ j(above, deferred->entry());
4546 __ SmiTag(reg);
4547 __ bind(deferred->exit());
4548}
4549
4550
4551void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4552 LOperand* value,
4553 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004554 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004555 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004556 Register tmp = reg.is(eax) ? ecx : eax;
4557
4558 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004559 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004560
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004561 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004562
4563 if (signedness == SIGNED_INT32) {
4564 // There was overflow, so bits 30 and 31 of the original integer
4565 // disagree. Try to allocate a heap number in new space and store
4566 // the value in there. If that fails, call the runtime system.
4567 __ SmiUntag(reg);
4568 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004569 if (CpuFeatures::IsSupported(SSE2)) {
4570 CpuFeatures::Scope feature_scope(SSE2);
4571 __ cvtsi2sd(xmm0, Operand(reg));
4572 } else {
4573 __ push(reg);
4574 __ fild_s(Operand(esp, 0));
4575 __ pop(reg);
4576 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004577 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004578 if (CpuFeatures::IsSupported(SSE2)) {
4579 CpuFeatures::Scope feature_scope(SSE2);
4580 __ LoadUint32(xmm0, reg, xmm1);
4581 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004582 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
4583 // int manually.
4584 __ push(Immediate(0));
4585 __ push(reg);
4586 __ fild_d(Operand(esp, 0));
4587 __ pop(reg);
4588 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004589 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004590 }
4591
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004592 if (FLAG_inline_new) {
4593 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004594 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004595 }
4596
4597 // Slow case: Call the runtime system to do the number allocation.
4598 __ bind(&slow);
4599
4600 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4601 // register is stored, as this register is in the pointer map, but contains an
4602 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004603 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004604 // NumberTagI and NumberTagD use the context from the frame, rather than
4605 // the environment's HContext or HInlinedContext value.
4606 // They only call Runtime::kAllocateHeapNumber.
4607 // The corresponding HChange instructions are added in a phase that does
4608 // not have easy access to the local context.
4609 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4610 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4611 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004612 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004613 if (!reg.is(eax)) __ mov(reg, eax);
4614
4615 // Done. Put the value in xmm0 into the value of the allocated heap
4616 // number.
4617 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004618 if (CpuFeatures::IsSupported(SSE2)) {
4619 CpuFeatures::Scope feature_scope(SSE2);
4620 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
4621 } else {
4622 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4623 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004624 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004625}
4626
4627
4628void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4629 class DeferredNumberTagD: public LDeferredCode {
4630 public:
4631 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4632 : LDeferredCode(codegen), instr_(instr) { }
4633 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004634 virtual LInstruction* instr() { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004635 private:
4636 LNumberTagD* instr_;
4637 };
4638
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004639 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004640
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004641 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004642 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00004643 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004644 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
4645 } else {
4646 __ jmp(deferred->entry());
4647 }
4648 __ bind(deferred->exit());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004649 if (CpuFeatures::IsSupported(SSE2)) {
4650 CpuFeatures::Scope scope(SSE2);
4651 XMMRegister input_reg = ToDoubleRegister(instr->value());
4652 __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
4653 } else {
4654 if (!IsX87TopOfStack(instr->value())) {
4655 __ fld_d(ToOperand(instr->value()));
4656 }
4657 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
4658 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004659}
4660
4661
4662void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4663 // TODO(3095996): Get rid of this. For now, we need to make the
4664 // result register contain a valid pointer because it is already
4665 // contained in the register pointer map.
4666 Register reg = ToRegister(instr->result());
4667 __ Set(reg, Immediate(0));
4668
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004669 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004670 // NumberTagI and NumberTagD use the context from the frame, rather than
4671 // the environment's HContext or HInlinedContext value.
4672 // They only call Runtime::kAllocateHeapNumber.
4673 // The corresponding HChange instructions are added in a phase that does
4674 // not have easy access to the local context.
4675 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4676 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00004677 RecordSafepointWithRegisters(
4678 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004679 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004680}
4681
4682
4683void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004684 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004685 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4686 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4687 __ SmiTag(ToRegister(input));
4688}
4689
4690
4691void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004692 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004693 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4694 if (instr->needs_check()) {
4695 __ test(ToRegister(input), Immediate(kSmiTagMask));
4696 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004697 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004698 __ AssertSmi(ToRegister(input));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004699 }
4700 __ SmiUntag(ToRegister(input));
4701}
4702
4703
4704void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004705 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004706 XMMRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004707 bool deoptimize_on_undefined,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004708 bool deoptimize_on_minus_zero,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004709 LEnvironment* env) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004710 Label load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004711
4712 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004713 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004714
4715 // Heap number map check.
4716 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004717 factory()->heap_number_map());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004718 if (deoptimize_on_undefined) {
4719 DeoptimizeIf(not_equal, env);
4720 } else {
4721 Label heap_number;
4722 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004723
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004724 __ cmp(input_reg, factory()->undefined_value());
4725 DeoptimizeIf(not_equal, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004726
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004727 // Convert undefined to NaN.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004728 ExternalReference nan =
4729 ExternalReference::address_of_canonical_non_hole_nan();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004730 __ movdbl(result_reg, Operand::StaticVariable(nan));
4731 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004732
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004733 __ bind(&heap_number);
4734 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004735 // Heap number to XMM conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004736 __ movdbl(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004737 if (deoptimize_on_minus_zero) {
4738 XMMRegister xmm_scratch = xmm0;
4739 __ xorps(xmm_scratch, xmm_scratch);
4740 __ ucomisd(result_reg, xmm_scratch);
4741 __ j(not_zero, &done, Label::kNear);
4742 __ movmskpd(temp_reg, result_reg);
4743 __ test_b(temp_reg, 1);
4744 DeoptimizeIf(not_zero, env);
4745 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004746 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004747
4748 // Smi to XMM conversion
4749 __ bind(&load_smi);
4750 __ SmiUntag(input_reg); // Untag smi before converting to float.
4751 __ cvtsi2sd(result_reg, Operand(input_reg));
4752 __ SmiTag(input_reg); // Retag smi.
4753 __ bind(&done);
4754}
4755
4756
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004757void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004758 Label done, heap_number;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004759 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004760
4761 // Heap number map check.
4762 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004763 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004764
4765 if (instr->truncating()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004766 __ j(equal, &heap_number, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004767 // Check for undefined. Undefined is converted to zero for truncating
4768 // conversions.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 __ cmp(input_reg, factory()->undefined_value());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004770 __ RecordComment("Deferred TaggedToI: cannot truncate");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004771 DeoptimizeIf(not_equal, instr->environment());
4772 __ mov(input_reg, 0);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004773 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004774
4775 __ bind(&heap_number);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004776 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004777 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004778 Label convert;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004779 // Use more powerful conversion when sse3 is available.
4780 // Load x87 register with heap number.
4781 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
4782 // Get exponent alone and check for too-big exponent.
4783 __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
4784 __ and_(input_reg, HeapNumber::kExponentMask);
4785 const uint32_t kTooBigExponent =
4786 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4787 __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004788 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004789 // Pop FPU stack before deoptimizing.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004790 __ fstp(0);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004791 __ RecordComment("Deferred TaggedToI: exponent too big");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004792 DeoptimizeIf(no_condition, instr->environment());
4793
4794 // Reserve space for 64 bit answer.
4795 __ bind(&convert);
4796 __ sub(Operand(esp), Immediate(kDoubleSize));
4797 // Do conversion, which cannot fail because we checked the exponent.
4798 __ fisttp_d(Operand(esp, 0));
4799 __ mov(input_reg, Operand(esp, 0)); // Low word of answer is the result.
4800 __ add(Operand(esp), Immediate(kDoubleSize));
4801 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004802 CpuFeatures::Scope scope(SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004803 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004804 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4805 __ cvttsd2si(input_reg, Operand(xmm0));
4806 __ cmp(input_reg, 0x80000000u);
4807 __ j(not_equal, &done);
4808 // Check if the input was 0x8000000 (kMinInt).
4809 // If no, then we got an overflow and we deoptimize.
4810 ExternalReference min_int = ExternalReference::address_of_min_int();
4811 __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
4812 __ ucomisd(xmm_temp, xmm0);
4813 DeoptimizeIf(not_equal, instr->environment());
4814 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4815 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004816 } else if (CpuFeatures::IsSupported(SSE2)) {
4817 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004818 // Deoptimize if we don't have a heap number.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004819 __ RecordComment("Deferred TaggedToI: not a heap number");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004820 DeoptimizeIf(not_equal, instr->environment());
4821
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004822 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004823 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
4824 __ cvttsd2si(input_reg, Operand(xmm0));
4825 __ cvtsi2sd(xmm_temp, Operand(input_reg));
4826 __ ucomisd(xmm0, xmm_temp);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004827 __ RecordComment("Deferred TaggedToI: lost precision");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004828 DeoptimizeIf(not_equal, instr->environment());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004829 __ RecordComment("Deferred TaggedToI: NaN");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004830 DeoptimizeIf(parity_even, instr->environment()); // NaN.
4831 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4832 __ test(input_reg, Operand(input_reg));
4833 __ j(not_zero, &done);
4834 __ movmskpd(input_reg, xmm0);
4835 __ and_(input_reg, 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004836 __ RecordComment("Deferred TaggedToI: minus zero");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004837 DeoptimizeIf(not_zero, instr->environment());
4838 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004839 } else {
4840 UNREACHABLE();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004841 }
4842 __ bind(&done);
4843}
4844
4845
4846void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004847 class DeferredTaggedToI: public LDeferredCode {
4848 public:
4849 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4850 : LDeferredCode(codegen), instr_(instr) { }
4851 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4852 virtual LInstruction* instr() { return instr_; }
4853 private:
4854 LTaggedToI* instr_;
4855 };
4856
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004857 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004858 ASSERT(input->IsRegister());
4859 ASSERT(input->Equals(instr->result()));
4860
4861 Register input_reg = ToRegister(input);
4862
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004863 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004864
4865 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004866 __ JumpIfNotSmi(input_reg, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004867
4868 // Smi to int32 conversion
4869 __ SmiUntag(input_reg); // Untag smi.
4870
4871 __ bind(deferred->exit());
4872}
4873
4874
4875void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004876 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004877 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004878 LOperand* temp = instr->temp();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004879 ASSERT(temp == NULL || temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004880 LOperand* result = instr->result();
4881 ASSERT(result->IsDoubleRegister());
4882
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004883 if (CpuFeatures::IsSupported(SSE2)) {
4884 CpuFeatures::Scope scope(SSE2);
4885 Register input_reg = ToRegister(input);
4886 XMMRegister result_reg = ToDoubleRegister(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004887
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004888 bool deoptimize_on_minus_zero =
4889 instr->hydrogen()->deoptimize_on_minus_zero();
4890 Register temp_reg = deoptimize_on_minus_zero ? ToRegister(temp) : no_reg;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004891
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004892 EmitNumberUntagD(input_reg,
4893 temp_reg,
4894 result_reg,
4895 instr->hydrogen()->deoptimize_on_undefined(),
4896 deoptimize_on_minus_zero,
4897 instr->environment());
4898 } else {
4899 UNIMPLEMENTED();
4900 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004901}
4902
4903
4904void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004905 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004906 ASSERT(input->IsDoubleRegister());
4907 LOperand* result = instr->result();
4908 ASSERT(result->IsRegister());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004909 CpuFeatures::Scope scope(SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004910
4911 XMMRegister input_reg = ToDoubleRegister(input);
4912 Register result_reg = ToRegister(result);
4913
4914 if (instr->truncating()) {
4915 // Performs a truncating conversion of a floating point number as used by
4916 // the JS bitwise operations.
4917 __ cvttsd2si(result_reg, Operand(input_reg));
4918 __ cmp(result_reg, 0x80000000u);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004919 if (CpuFeatures::IsSupported(SSE3)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004920 // This will deoptimize if the exponent of the input in out of range.
4921 CpuFeatures::Scope scope(SSE3);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004922 Label convert, done;
4923 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004924 __ sub(Operand(esp), Immediate(kDoubleSize));
4925 __ movdbl(Operand(esp, 0), input_reg);
4926 // Get exponent alone and check for too-big exponent.
4927 __ mov(result_reg, Operand(esp, sizeof(int32_t)));
4928 __ and_(result_reg, HeapNumber::kExponentMask);
4929 const uint32_t kTooBigExponent =
4930 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
4931 __ cmp(Operand(result_reg), Immediate(kTooBigExponent));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004932 __ j(less, &convert, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004933 __ add(Operand(esp), Immediate(kDoubleSize));
4934 DeoptimizeIf(no_condition, instr->environment());
4935 __ bind(&convert);
4936 // Do conversion, which cannot fail because we checked the exponent.
4937 __ fld_d(Operand(esp, 0));
4938 __ fisttp_d(Operand(esp, 0));
4939 __ mov(result_reg, Operand(esp, 0)); // Low word of answer is the result.
4940 __ add(Operand(esp), Immediate(kDoubleSize));
4941 __ bind(&done);
4942 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004943 Label done;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004944 Register temp_reg = ToRegister(instr->temp());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004945 XMMRegister xmm_scratch = xmm0;
4946
4947 // If cvttsd2si succeeded, we're done. Otherwise, we attempt
4948 // manual conversion.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004949 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004950
4951 // Get high 32 bits of the input in result_reg and temp_reg.
4952 __ pshufd(xmm_scratch, input_reg, 1);
4953 __ movd(Operand(temp_reg), xmm_scratch);
4954 __ mov(result_reg, temp_reg);
4955
4956 // Prepare negation mask in temp_reg.
4957 __ sar(temp_reg, kBitsPerInt - 1);
4958
4959 // Extract the exponent from result_reg and subtract adjusted
4960 // bias from it. The adjustment is selected in a way such that
4961 // when the difference is zero, the answer is in the low 32 bits
4962 // of the input, otherwise a shift has to be performed.
4963 __ shr(result_reg, HeapNumber::kExponentShift);
4964 __ and_(result_reg,
4965 HeapNumber::kExponentMask >> HeapNumber::kExponentShift);
4966 __ sub(Operand(result_reg),
4967 Immediate(HeapNumber::kExponentBias +
4968 HeapNumber::kExponentBits +
4969 HeapNumber::kMantissaBits));
4970 // Don't handle big (> kMantissaBits + kExponentBits == 63) or
4971 // special exponents.
4972 DeoptimizeIf(greater, instr->environment());
4973
4974 // Zero out the sign and the exponent in the input (by shifting
4975 // it to the left) and restore the implicit mantissa bit,
4976 // i.e. convert the input to unsigned int64 shifted left by
4977 // kExponentBits.
4978 ExternalReference minus_zero = ExternalReference::address_of_minus_zero();
4979 // Minus zero has the most significant bit set and the other
4980 // bits cleared.
4981 __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero));
4982 __ psllq(input_reg, HeapNumber::kExponentBits);
4983 __ por(input_reg, xmm_scratch);
4984
4985 // Get the amount to shift the input right in xmm_scratch.
4986 __ neg(result_reg);
4987 __ movd(xmm_scratch, Operand(result_reg));
4988
4989 // Shift the input right and extract low 32 bits.
4990 __ psrlq(input_reg, xmm_scratch);
4991 __ movd(Operand(result_reg), input_reg);
4992
4993 // Use the prepared mask in temp_reg to negate the result if necessary.
4994 __ xor_(result_reg, Operand(temp_reg));
4995 __ sub(result_reg, Operand(temp_reg));
4996 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004997 }
4998 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004999 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000 __ cvttsd2si(result_reg, Operand(input_reg));
5001 __ cvtsi2sd(xmm0, Operand(result_reg));
5002 __ ucomisd(xmm0, input_reg);
5003 DeoptimizeIf(not_equal, instr->environment());
5004 DeoptimizeIf(parity_even, instr->environment()); // NaN.
5005 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5006 // The integer converted back is equal to the original. We
5007 // only have to test if we got -0 as an input.
5008 __ test(result_reg, Operand(result_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005009 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005010 __ movmskpd(result_reg, input_reg);
5011 // Bit 0 contains the sign of the double in input_reg.
5012 // If input was positive, we are ok and return 0, otherwise
5013 // deoptimize.
5014 __ and_(result_reg, 1);
5015 DeoptimizeIf(not_zero, instr->environment());
5016 }
5017 __ bind(&done);
5018 }
5019}
5020
5021
5022void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005023 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005024 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005025 DeoptimizeIf(not_zero, instr->environment());
5026}
5027
5028
5029void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005030 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005031 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005032 DeoptimizeIf(zero, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005033}
5034
5035
5036void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005037 Register input = ToRegister(instr->value());
5038 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005040 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005041
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005042 if (instr->hydrogen()->is_interval_check()) {
5043 InstanceType first;
5044 InstanceType last;
5045 instr->hydrogen()->GetCheckInterval(&first, &last);
5046
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005047 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5048 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005049
5050 // If there is only one type in the interval check for equality.
5051 if (first == last) {
5052 DeoptimizeIf(not_equal, instr->environment());
5053 } else {
5054 DeoptimizeIf(below, instr->environment());
5055 // Omit check for the last type.
5056 if (last != LAST_TYPE) {
5057 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5058 static_cast<int8_t>(last));
5059 DeoptimizeIf(above, instr->environment());
5060 }
5061 }
5062 } else {
5063 uint8_t mask;
5064 uint8_t tag;
5065 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5066
5067 if (IsPowerOf2(mask)) {
5068 ASSERT(tag == 0 || IsPowerOf2(tag));
5069 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5070 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5071 } else {
5072 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5073 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005074 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005075 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005076 }
5077 }
5078}
5079
5080
5081void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005082 Handle<JSFunction> target = instr->hydrogen()->target();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005083 if (instr->hydrogen()->target_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005084 Register reg = ToRegister(instr->value());
5085 Handle<JSGlobalPropertyCell> cell =
5086 isolate()->factory()->NewJSGlobalPropertyCell(target);
5087 __ cmp(reg, Operand::Cell(cell));
5088 } else {
5089 Operand operand = ToOperand(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005090 __ cmp(operand, target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005091 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092 DeoptimizeIf(not_equal, instr->environment());
5093}
5094
5095
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005096void LCodeGen::DoCheckMapCommon(Register reg,
5097 Handle<Map> map,
5098 CompareMapMode mode,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005099 LInstruction* instr) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005100 Label success;
5101 __ CompareMap(reg, map, &success, mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005102 DeoptimizeIf(not_equal, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005103 __ bind(&success);
5104}
5105
5106
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005107void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005108 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005109 ASSERT(input->IsRegister());
5110 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005111
5112 Label success;
5113 SmallMapList* map_set = instr->hydrogen()->map_set();
5114 for (int i = 0; i < map_set->length() - 1; i++) {
5115 Handle<Map> map = map_set->at(i);
5116 __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
5117 __ j(equal, &success);
5118 }
5119 Handle<Map> map = map_set->last();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005120 DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005121 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005122}
5123
5124
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005125void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005126 CpuFeatures::Scope scope(SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005127 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
5128 Register result_reg = ToRegister(instr->result());
5129 __ ClampDoubleToUint8(value_reg, xmm0, result_reg);
5130}
5131
5132
5133void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5134 ASSERT(instr->unclamped()->Equals(instr->result()));
5135 Register value_reg = ToRegister(instr->result());
5136 __ ClampUint8(value_reg);
5137}
5138
5139
5140void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005141 CpuFeatures::Scope scope(SSE2);
5142
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005143 ASSERT(instr->unclamped()->Equals(instr->result()));
5144 Register input_reg = ToRegister(instr->unclamped());
5145 Label is_smi, done, heap_number;
5146
5147 __ JumpIfSmi(input_reg, &is_smi);
5148
5149 // Check for heap number
5150 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5151 factory()->heap_number_map());
5152 __ j(equal, &heap_number, Label::kNear);
5153
5154 // Check for undefined. Undefined is converted to zero for clamping
5155 // conversions.
5156 __ cmp(input_reg, factory()->undefined_value());
5157 DeoptimizeIf(not_equal, instr->environment());
5158 __ mov(input_reg, 0);
5159 __ jmp(&done, Label::kNear);
5160
5161 // Heap number
5162 __ bind(&heap_number);
5163 __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
5164 __ ClampDoubleToUint8(xmm0, xmm1, input_reg);
5165 __ jmp(&done, Label::kNear);
5166
5167 // smi
5168 __ bind(&is_smi);
5169 __ SmiUntag(input_reg);
5170 __ ClampUint8(input_reg);
5171
5172 __ bind(&done);
5173}
5174
5175
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005176void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00005177 ASSERT(instr->temp()->Equals(instr->result()));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005178 Register reg = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005179
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005180 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5181 ZoneList<Handle<Map> >* maps = instr->maps();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005182
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005183 ASSERT(prototypes->length() == maps->length());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005184
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00005185 for (int i = 0; i < prototypes->length(); i++) {
5186 __ LoadHeapObject(reg, prototypes->at(i));
5187 DoCheckMapCommon(reg, maps->at(i), ALLOW_ELEMENT_TRANSITION_MAPS, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005188 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005189}
5190
5191
ulan@chromium.org967e2702012-02-28 09:49:15 +00005192void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
5193 class DeferredAllocateObject: public LDeferredCode {
5194 public:
5195 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
5196 : LDeferredCode(codegen), instr_(instr) { }
5197 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
5198 virtual LInstruction* instr() { return instr_; }
5199 private:
5200 LAllocateObject* instr_;
5201 };
5202
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005203 DeferredAllocateObject* deferred =
5204 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005205
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005206 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005207 Register scratch = ToRegister(instr->temp());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005208 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
5209 Handle<Map> initial_map(constructor->initial_map());
5210 int instance_size = initial_map->instance_size();
5211 ASSERT(initial_map->pre_allocated_property_fields() +
5212 initial_map->unused_property_fields() -
5213 initial_map->inobject_properties() == 0);
5214
5215 // Allocate memory for the object. The initial map might change when
5216 // the constructor's prototype changes, but instance size and property
5217 // counts remain unchanged (if slack tracking finished).
5218 ASSERT(!constructor->shared()->IsInobjectSlackTrackingInProgress());
5219 __ AllocateInNewSpace(instance_size,
5220 result,
5221 no_reg,
5222 scratch,
5223 deferred->entry(),
5224 TAG_OBJECT);
5225
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005226 __ bind(deferred->exit());
5227 if (FLAG_debug_code) {
5228 Label is_in_new_space;
5229 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
5230 __ Abort("Allocated object is not in new-space");
5231 __ bind(&is_in_new_space);
5232 }
5233
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005234 // Load the initial map.
5235 Register map = scratch;
5236 __ LoadHeapObject(scratch, constructor);
5237 __ mov(map, FieldOperand(scratch, JSFunction::kPrototypeOrInitialMapOffset));
5238
5239 if (FLAG_debug_code) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005240 __ AssertNotSmi(map);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005241 __ cmpb(FieldOperand(map, Map::kInstanceSizeOffset),
5242 instance_size >> kPointerSizeLog2);
5243 __ Assert(equal, "Unexpected instance size");
5244 __ cmpb(FieldOperand(map, Map::kPreAllocatedPropertyFieldsOffset),
5245 initial_map->pre_allocated_property_fields());
5246 __ Assert(equal, "Unexpected pre-allocated property fields count");
5247 __ cmpb(FieldOperand(map, Map::kUnusedPropertyFieldsOffset),
5248 initial_map->unused_property_fields());
5249 __ Assert(equal, "Unexpected unused property fields count");
5250 __ cmpb(FieldOperand(map, Map::kInObjectPropertiesOffset),
5251 initial_map->inobject_properties());
5252 __ Assert(equal, "Unexpected in-object property fields count");
5253 }
5254
5255 // Initialize map and fields of the newly allocated object.
5256 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
5257 __ mov(FieldOperand(result, JSObject::kMapOffset), map);
5258 __ mov(scratch, factory()->empty_fixed_array());
5259 __ mov(FieldOperand(result, JSObject::kElementsOffset), scratch);
5260 __ mov(FieldOperand(result, JSObject::kPropertiesOffset), scratch);
5261 if (initial_map->inobject_properties() != 0) {
5262 __ mov(scratch, factory()->undefined_value());
5263 for (int i = 0; i < initial_map->inobject_properties(); i++) {
5264 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
5265 __ mov(FieldOperand(result, property_offset), scratch);
5266 }
5267 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00005268}
5269
5270
5271void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
5272 Register result = ToRegister(instr->result());
5273 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005274 Handle<Map> initial_map(constructor->initial_map());
5275 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00005276
5277 // TODO(3095996): Get rid of this. For now, we need to make the
5278 // result register contain a valid pointer because it is already
5279 // contained in the register pointer map.
5280 __ Set(result, Immediate(0));
5281
5282 PushSafepointRegistersScope scope(this);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005283 __ push(Immediate(Smi::FromInt(instance_size)));
5284 CallRuntimeFromDeferred(
5285 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
ulan@chromium.org967e2702012-02-28 09:49:15 +00005286 __ StoreToSafepointRegisterSlot(result, eax);
5287}
5288
5289
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005290void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005291 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005292 Handle<FixedArray> literals(instr->environment()->closure()->literals());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005293 ElementsKind boilerplate_elements_kind =
5294 instr->hydrogen()->boilerplate_elements_kind();
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005295 AllocationSiteMode allocation_site_mode =
5296 instr->hydrogen()->allocation_site_mode();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005297
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005298 // Deopt if the array literal boilerplate ElementsKind is of a type different
5299 // than the expected one. The check isn't necessary if the boilerplate has
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005300 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5301 if (CanTransitionToMoreGeneralFastElementsKind(
5302 boilerplate_elements_kind, true)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005303 __ LoadHeapObject(eax, instr->hydrogen()->boilerplate_object());
5304 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
5305 // Load the map's "bit field 2". We only need the first byte,
5306 // but the following masking takes care of that anyway.
5307 __ mov(ebx, FieldOperand(ebx, Map::kBitField2Offset));
5308 // Retrieve elements_kind from bit field 2.
5309 __ and_(ebx, Map::kElementsKindMask);
5310 __ cmp(ebx, boilerplate_elements_kind << Map::kElementsKindShift);
5311 DeoptimizeIf(not_equal, instr->environment());
5312 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005313
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005314 // Set up the parameters to the stub/runtime call.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005315 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005316 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005317 // Boilerplate already exists, constant elements are never accessed.
5318 // Pass an empty fixed array.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005319 __ push(Immediate(isolate()->factory()->empty_fixed_array()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005320
5321 // Pick the right runtime function or stub to call.
5322 int length = instr->hydrogen()->length();
5323 if (instr->hydrogen()->IsCopyOnWrite()) {
5324 ASSERT(instr->hydrogen()->depth() == 1);
5325 FastCloneShallowArrayStub::Mode mode =
5326 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005327 FastCloneShallowArrayStub stub(mode, DONT_TRACK_ALLOCATION_SITE, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005328 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005329 } else if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005330 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005331 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005332 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005333 } else {
5334 FastCloneShallowArrayStub::Mode mode =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005335 boilerplate_elements_kind == FAST_DOUBLE_ELEMENTS
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005336 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS
5337 : FastCloneShallowArrayStub::CLONE_ELEMENTS;
5338 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005339 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005340 }
5341}
5342
5343
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005344void LCodeGen::EmitDeepCopy(Handle<JSObject> object,
5345 Register result,
5346 Register source,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005347 int* offset,
5348 AllocationSiteMode mode) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005349 ASSERT(!source.is(ecx));
5350 ASSERT(!result.is(ecx));
5351
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005352 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
5353 object->map()->CanTrackAllocationSite();
5354
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005355 if (FLAG_debug_code) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005356 __ LoadHeapObject(ecx, object);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005357 __ cmp(source, ecx);
5358 __ Assert(equal, "Unexpected object literal boilerplate");
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005359 __ mov(ecx, FieldOperand(source, HeapObject::kMapOffset));
5360 __ cmp(ecx, Handle<Map>(object->map()));
5361 __ Assert(equal, "Unexpected boilerplate map");
5362 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5363 __ and_(ecx, Map::kElementsKindMask);
5364 __ cmp(ecx, object->GetElementsKind() << Map::kElementsKindShift);
5365 __ Assert(equal, "Unexpected boilerplate elements kind");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005366 }
5367
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005368 // Only elements backing stores for non-COW arrays need to be copied.
5369 Handle<FixedArrayBase> elements(object->elements());
5370 bool has_elements = elements->length() > 0 &&
5371 elements->map() != isolate()->heap()->fixed_cow_array_map();
5372
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005373 // Increase the offset so that subsequent objects end up right after
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005374 // this object and its backing store.
5375 int object_offset = *offset;
5376 int object_size = object->map()->instance_size();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005377 int elements_size = has_elements ? elements->Size() : 0;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005378 int elements_offset = *offset + object_size;
5379 if (create_allocation_site_info) {
5380 elements_offset += AllocationSiteInfo::kSize;
5381 *offset += AllocationSiteInfo::kSize;
5382 }
5383
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005384 *offset += object_size + elements_size;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005385
5386 // Copy object header.
5387 ASSERT(object->properties()->length() == 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005388 int inobject_properties = object->map()->inobject_properties();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005389 int header_size = object_size - inobject_properties * kPointerSize;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005390 for (int i = 0; i < header_size; i += kPointerSize) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005391 if (has_elements && i == JSObject::kElementsOffset) {
5392 __ lea(ecx, Operand(result, elements_offset));
5393 } else {
5394 __ mov(ecx, FieldOperand(source, i));
5395 }
5396 __ mov(FieldOperand(result, object_offset + i), ecx);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005397 }
5398
5399 // Copy in-object properties.
5400 for (int i = 0; i < inobject_properties; i++) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005401 int total_offset = object_offset + object->GetInObjectPropertyOffset(i);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005402 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i));
5403 if (value->IsJSObject()) {
5404 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5405 __ lea(ecx, Operand(result, *offset));
5406 __ mov(FieldOperand(result, total_offset), ecx);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005407 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005408 EmitDeepCopy(value_object, result, source, offset,
5409 DONT_TRACK_ALLOCATION_SITE);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005410 } else if (value->IsHeapObject()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005411 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005412 __ mov(FieldOperand(result, total_offset), ecx);
5413 } else {
5414 __ mov(FieldOperand(result, total_offset), Immediate(value));
5415 }
5416 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005417
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005418 // Build Allocation Site Info if desired
5419 if (create_allocation_site_info) {
5420 __ mov(FieldOperand(result, object_size),
5421 Immediate(Handle<Map>(isolate()->heap()->
5422 allocation_site_info_map())));
5423 __ mov(FieldOperand(result, object_size + kPointerSize), source);
5424 }
5425
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005426 if (has_elements) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005427 // Copy elements backing store header.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005428 __ LoadHeapObject(source, elements);
5429 for (int i = 0; i < FixedArray::kHeaderSize; i += kPointerSize) {
5430 __ mov(ecx, FieldOperand(source, i));
5431 __ mov(FieldOperand(result, elements_offset + i), ecx);
5432 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005433
danno@chromium.org88aa0582012-03-23 15:11:57 +00005434 // Copy elements backing store content.
5435 int elements_length = elements->length();
5436 if (elements->IsFixedDoubleArray()) {
5437 Handle<FixedDoubleArray> double_array =
5438 Handle<FixedDoubleArray>::cast(elements);
5439 for (int i = 0; i < elements_length; i++) {
5440 int64_t value = double_array->get_representation(i);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005441 int32_t value_low = static_cast<int32_t>(value & 0xFFFFFFFF);
5442 int32_t value_high = static_cast<int32_t>(value >> 32);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005443 int total_offset =
5444 elements_offset + FixedDoubleArray::OffsetOfElementAt(i);
5445 __ mov(FieldOperand(result, total_offset), Immediate(value_low));
5446 __ mov(FieldOperand(result, total_offset + 4), Immediate(value_high));
5447 }
5448 } else if (elements->IsFixedArray()) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005449 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005450 for (int i = 0; i < elements_length; i++) {
5451 int total_offset = elements_offset + FixedArray::OffsetOfElementAt(i);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00005452 Handle<Object> value(fast_elements->get(i));
danno@chromium.org88aa0582012-03-23 15:11:57 +00005453 if (value->IsJSObject()) {
5454 Handle<JSObject> value_object = Handle<JSObject>::cast(value);
5455 __ lea(ecx, Operand(result, *offset));
5456 __ mov(FieldOperand(result, total_offset), ecx);
5457 __ LoadHeapObject(source, value_object);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005458 EmitDeepCopy(value_object, result, source, offset,
5459 DONT_TRACK_ALLOCATION_SITE);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005460 } else if (value->IsHeapObject()) {
5461 __ LoadHeapObject(ecx, Handle<HeapObject>::cast(value));
5462 __ mov(FieldOperand(result, total_offset), ecx);
5463 } else {
5464 __ mov(FieldOperand(result, total_offset), Immediate(value));
5465 }
5466 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005467 } else {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005468 UNREACHABLE();
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005469 }
5470 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005471}
5472
5473
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005474void LCodeGen::DoFastLiteral(LFastLiteral* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005475 ASSERT(ToRegister(instr->context()).is(esi));
5476 int size = instr->hydrogen()->total_size();
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005477 ElementsKind boilerplate_elements_kind =
5478 instr->hydrogen()->boilerplate()->GetElementsKind();
5479
5480 // Deopt if the literal boilerplate ElementsKind is of a type different than
5481 // the expected one. The check isn't necessary if the boilerplate has already
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005482 // already been converted to TERMINAL_FAST_ELEMENTS_KIND.
5483 if (CanTransitionToMoreGeneralFastElementsKind(
5484 boilerplate_elements_kind, true)) {
danno@chromium.org2c26cb12012-05-03 09:06:43 +00005485 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
5486 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset));
5487 // Load the map's "bit field 2". We only need the first byte,
5488 // but the following masking takes care of that anyway.
5489 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset));
5490 // Retrieve elements_kind from bit field 2.
5491 __ and_(ecx, Map::kElementsKindMask);
5492 __ cmp(ecx, boilerplate_elements_kind << Map::kElementsKindShift);
5493 DeoptimizeIf(not_equal, instr->environment());
5494 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005495
5496 // Allocate all objects that are part of the literal in one big
5497 // allocation. This avoids multiple limit checks.
5498 Label allocated, runtime_allocate;
5499 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5500 __ jmp(&allocated);
5501
5502 __ bind(&runtime_allocate);
5503 __ push(Immediate(Smi::FromInt(size)));
5504 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5505
5506 __ bind(&allocated);
5507 int offset = 0;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005508 __ LoadHeapObject(ebx, instr->hydrogen()->boilerplate());
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005509 EmitDeepCopy(instr->hydrogen()->boilerplate(), eax, ebx, &offset,
5510 instr->hydrogen()->allocation_site_mode());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005511 ASSERT_EQ(size, offset);
5512}
5513
5514
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005515void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005516 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005517 Handle<FixedArray> literals(instr->environment()->closure()->literals());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005518 Handle<FixedArray> constant_properties =
5519 instr->hydrogen()->constant_properties();
5520
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005521 // Set up the parameters to the stub/runtime call.
ulan@chromium.org65a89c22012-02-14 11:46:07 +00005522 __ PushHeapObject(literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005523 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005524 __ push(Immediate(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005525 int flags = instr->hydrogen()->fast_elements()
5526 ? ObjectLiteral::kFastElements
5527 : ObjectLiteral::kNoFlags;
5528 flags |= instr->hydrogen()->has_function()
5529 ? ObjectLiteral::kHasFunction
5530 : ObjectLiteral::kNoFlags;
5531 __ push(Immediate(Smi::FromInt(flags)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005532
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005533 // Pick the right runtime function or stub to call.
5534 int properties_count = constant_properties->length() / 2;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005535 if (instr->hydrogen()->depth() > 1) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005536 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005537 } else if (flags != ObjectLiteral::kFastElements ||
5538 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005539 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00005540 } else {
5541 FastCloneShallowObjectStub stub(properties_count);
5542 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005543 }
5544}
5545
5546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005547void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005548 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005549 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005550 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005551}
5552
5553
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005554void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005555 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005556 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005557 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005558 // ecx = literals array.
5559 // ebx = regexp literal.
5560 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005561 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005562 int literal_offset =
5563 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5564 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005565 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005566 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005567 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005568
5569 // Create regexp literal using runtime function
5570 // Result will be in eax.
5571 __ push(ecx);
5572 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5573 __ push(Immediate(instr->hydrogen()->pattern()));
5574 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005575 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005576 __ mov(ebx, eax);
5577
5578 __ bind(&materialized);
5579 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5580 Label allocated, runtime_allocate;
5581 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
5582 __ jmp(&allocated);
5583
5584 __ bind(&runtime_allocate);
5585 __ push(ebx);
5586 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005587 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005588 __ pop(ebx);
5589
5590 __ bind(&allocated);
5591 // Copy the content into the newly allocated memory.
5592 // (Unroll copy loop once for better throughput).
5593 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5594 __ mov(edx, FieldOperand(ebx, i));
5595 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5596 __ mov(FieldOperand(eax, i), edx);
5597 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5598 }
5599 if ((size % (2 * kPointerSize)) != 0) {
5600 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
5601 __ mov(FieldOperand(eax, size - kPointerSize), edx);
5602 }
5603}
5604
5605
5606void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005607 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005608 // Use the fast case closure allocation code that allocates in new
5609 // space for nested functions that don't need literals cloning.
5610 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005611 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612 if (!pretenure && shared_info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005613 FastNewClosureStub stub(shared_info->language_mode());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614 __ push(Immediate(shared_info));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005615 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005616 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005617 __ push(esi);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005618 __ push(Immediate(shared_info));
5619 __ push(Immediate(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005620 ? factory()->true_value()
5621 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005622 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005623 }
5624}
5625
5626
5627void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005628 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005629 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005630 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631}
5632
5633
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005635 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636 int true_block = chunk_->LookupDestination(instr->true_block_id());
5637 int false_block = chunk_->LookupDestination(instr->false_block_id());
5638 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5639 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5640
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005641 Condition final_branch_condition =
5642 EmitTypeofIs(true_label, false_label, input, instr->type_literal());
5643 if (final_branch_condition != no_condition) {
5644 EmitBranch(true_block, false_block, final_branch_condition);
5645 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646}
5647
5648
5649Condition LCodeGen::EmitTypeofIs(Label* true_label,
5650 Label* false_label,
5651 Register input,
5652 Handle<String> type_name) {
5653 Condition final_branch_condition = no_condition;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005654 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005655 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005657 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005658 final_branch_condition = equal;
5659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005660 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005661 __ JumpIfSmi(input, false_label);
5662 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5663 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5665 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005666 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005667
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005668 } else if (type_name->Equals(heap()->boolean_symbol())) {
5669 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005670 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005672 final_branch_condition = equal;
5673
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005674 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
5675 __ cmp(input, factory()->null_value());
5676 final_branch_condition = equal;
5677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005678 } else if (type_name->Equals(heap()->undefined_symbol())) {
5679 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005680 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005681 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005682 // Check for undetectable objects => true.
5683 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
5684 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5685 1 << Map::kIsUndetectable);
5686 final_branch_condition = not_zero;
5687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005688 } else if (type_name->Equals(heap()->function_symbol())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005689 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005690 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005691 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5692 __ j(equal, true_label);
5693 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5694 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005695
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005696 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005697 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005698 if (!FLAG_harmony_typeof) {
5699 __ cmp(input, factory()->null_value());
5700 __ j(equal, true_label);
5701 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005702 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005703 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005704 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5705 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005706 // Check for undetectable objects => false.
5707 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
5708 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005709 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005710
5711 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005712 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005713 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005714 return final_branch_condition;
5715}
5716
5717
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005718void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005719 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005720 int true_block = chunk_->LookupDestination(instr->true_block_id());
5721 int false_block = chunk_->LookupDestination(instr->false_block_id());
5722
5723 EmitIsConstructCall(temp);
5724 EmitBranch(true_block, false_block, equal);
5725}
5726
5727
5728void LCodeGen::EmitIsConstructCall(Register temp) {
5729 // Get the frame pointer for the calling frame.
5730 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
5731
5732 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005733 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005734 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5735 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005736 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005737 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
5738
5739 // Check the marker in the calling frame.
5740 __ bind(&check_frame_marker);
5741 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5742 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
5743}
5744
5745
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005746void LCodeGen::EnsureSpaceForLazyDeopt() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005747 if (!info()->IsStub()) {
5748 // Ensure that we have enough space after the previous lazy-bailout
5749 // instruction for patching the code here.
5750 int current_pc = masm()->pc_offset();
5751 int patch_size = Deoptimizer::patch_size();
5752 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5753 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
5754 __ Nop(padding_size);
5755 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005756 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005757 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005758}
5759
5760
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005761void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005762 EnsureSpaceForLazyDeopt();
5763 ASSERT(instr->HasEnvironment());
5764 LEnvironment* env = instr->environment();
5765 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5766 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005767}
5768
5769
5770void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
5771 DeoptimizeIf(no_condition, instr->environment());
5772}
5773
5774
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005775void LCodeGen::DoDummyUse(LDummyUse* instr) {
5776 // Nothing to see here, move on!
5777}
5778
5779
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005780void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5781 LOperand* obj = instr->object();
5782 LOperand* key = instr->key();
5783 __ push(ToOperand(obj));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005784 EmitPushTaggedOperand(key);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005785 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005786 LPointerMap* pointers = instr->pointer_map();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00005787 RecordPosition(pointers->position());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005788 // Create safepoint generator that will also ensure enough space in the
5789 // reloc info for patching in deoptimization (since this is invoking a
5790 // builtin)
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005791 SafepointGenerator safepoint_generator(
5792 this, pointers, Safepoint::kLazyDeopt);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005793 __ push(Immediate(Smi::FromInt(strict_mode_flag())));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005794 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795}
5796
5797
ager@chromium.org04921a82011-06-27 13:21:41 +00005798void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005799 PushSafepointRegistersScope scope(this);
5800 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5801 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5802 RecordSafepointWithLazyDeopt(
5803 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5804 ASSERT(instr->HasEnvironment());
5805 LEnvironment* env = instr->environment();
5806 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005807}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005808
ager@chromium.org04921a82011-06-27 13:21:41 +00005809
5810void LCodeGen::DoStackCheck(LStackCheck* instr) {
5811 class DeferredStackCheck: public LDeferredCode {
5812 public:
5813 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5814 : LDeferredCode(codegen), instr_(instr) { }
5815 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005816 virtual LInstruction* instr() { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005817 private:
5818 LStackCheck* instr_;
5819 };
5820
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005821 ASSERT(instr->HasEnvironment());
5822 LEnvironment* env = instr->environment();
5823 // There is no LLazyBailout instruction for stack-checks. We have to
5824 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005825 if (instr->hydrogen()->is_function_entry()) {
5826 // Perform stack overflow check.
5827 Label done;
5828 ExternalReference stack_limit =
5829 ExternalReference::address_of_stack_limit(isolate());
5830 __ cmp(esp, Operand::StaticVariable(stack_limit));
5831 __ j(above_equal, &done, Label::kNear);
5832
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005833 ASSERT(instr->context()->IsRegister());
5834 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org04921a82011-06-27 13:21:41 +00005835 StackCheckStub stub;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005836 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005837 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005838 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005839 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5840 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005841 } else {
5842 ASSERT(instr->hydrogen()->is_backwards_branch());
5843 // Perform stack overflow check if this goto needs it before jumping.
5844 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005845 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005846 ExternalReference stack_limit =
5847 ExternalReference::address_of_stack_limit(isolate());
5848 __ cmp(esp, Operand::StaticVariable(stack_limit));
5849 __ j(below, deferred_stack_check->entry());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005850 EnsureSpaceForLazyDeopt();
ager@chromium.org04921a82011-06-27 13:21:41 +00005851 __ bind(instr->done_label());
5852 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005853 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5854 // Don't record a deoptimization index for the safepoint here.
5855 // This will be done explicitly when emitting call and the safepoint in
5856 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005857 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005858}
5859
5860
5861void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5862 // This is a pseudo-instruction that ensures that the environment here is
5863 // properly registered for deoptimization and records the assembler's PC
5864 // offset.
5865 LEnvironment* environment = instr->environment();
5866 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
5867 instr->SpilledDoubleRegisterArray());
5868
5869 // If the environment were already registered, we would have no way of
5870 // backpatching it with the spill slot operands.
5871 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005872 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005873 ASSERT(osr_pc_offset_ == -1);
5874 osr_pc_offset_ = masm()->pc_offset();
5875}
5876
5877
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005878void LCodeGen::DoIn(LIn* instr) {
5879 LOperand* obj = instr->object();
5880 LOperand* key = instr->key();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005881 EmitPushTaggedOperand(key);
5882 EmitPushTaggedOperand(obj);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00005883 ASSERT(instr->HasPointerMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005884 LPointerMap* pointers = instr->pointer_map();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005885 RecordPosition(pointers->position());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005886 SafepointGenerator safepoint_generator(
5887 this, pointers, Safepoint::kLazyDeopt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00005888 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005889}
5890
5891
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005892void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5893 __ cmp(eax, isolate()->factory()->undefined_value());
5894 DeoptimizeIf(equal, instr->environment());
5895
5896 __ cmp(eax, isolate()->factory()->null_value());
5897 DeoptimizeIf(equal, instr->environment());
5898
5899 __ test(eax, Immediate(kSmiTagMask));
5900 DeoptimizeIf(zero, instr->environment());
5901
5902 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5903 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
5904 DeoptimizeIf(below_equal, instr->environment());
5905
5906 Label use_cache, call_runtime;
5907 __ CheckEnumCache(&call_runtime);
5908
5909 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
5910 __ jmp(&use_cache, Label::kNear);
5911
5912 // Get the set of properties to enumerate.
5913 __ bind(&call_runtime);
5914 __ push(eax);
5915 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5916
5917 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
5918 isolate()->factory()->meta_map());
5919 DeoptimizeIf(not_equal, instr->environment());
5920 __ bind(&use_cache);
5921}
5922
5923
5924void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5925 Register map = ToRegister(instr->map());
5926 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005927 Label load_cache, done;
5928 __ EnumLength(result, map);
5929 __ cmp(result, Immediate(Smi::FromInt(0)));
5930 __ j(not_equal, &load_cache);
5931 __ mov(result, isolate()->factory()->empty_fixed_array());
5932 __ jmp(&done);
5933
5934 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005935 __ LoadInstanceDescriptors(map, result);
5936 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005937 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005938 __ mov(result,
5939 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005940 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005941 __ test(result, result);
5942 DeoptimizeIf(equal, instr->environment());
5943}
5944
5945
5946void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5947 Register object = ToRegister(instr->value());
5948 __ cmp(ToRegister(instr->map()),
5949 FieldOperand(object, HeapObject::kMapOffset));
5950 DeoptimizeIf(not_equal, instr->environment());
5951}
5952
5953
5954void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5955 Register object = ToRegister(instr->object());
5956 Register index = ToRegister(instr->index());
5957
5958 Label out_of_object, done;
5959 __ cmp(index, Immediate(0));
5960 __ j(less, &out_of_object);
5961 __ mov(object, FieldOperand(object,
5962 index,
5963 times_half_pointer_size,
5964 JSObject::kHeaderSize));
5965 __ jmp(&done, Label::kNear);
5966
5967 __ bind(&out_of_object);
5968 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
5969 __ neg(index);
5970 // Index is now equal to out of object property index plus 1.
5971 __ mov(object, FieldOperand(object,
5972 index,
5973 times_half_pointer_size,
5974 FixedArray::kHeaderSize - kPointerSize));
5975 __ bind(&done);
5976}
5977
5978
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005979#undef __
5980
5981} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005982
5983#endif // V8_TARGET_ARCH_IA32