blob: 46c87e1d62a9686627ec995c363fb87d6d7e5d41 [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000031
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"
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000038#include "hydrogen-osr.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000039
40namespace v8 {
41namespace internal {
42
43
ulan@chromium.org750145a2013-03-07 15:14:13 +000044static SaveFPRegsMode GetSaveFPRegsMode() {
45 // We don't need to save floating point regs when generating the snapshot
46 return CpuFeatures::IsSafeForSnapshot(SSE2) ? kSaveFPRegs : kDontSaveFPRegs;
47}
48
49
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000050// When invoking builtins, we need to record the safepoint in the middle of
51// the invoke instruction sequence generated by the macro assembler.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000052class SafepointGenerator V8_FINAL : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053 public:
54 SafepointGenerator(LCodeGen* codegen,
55 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000056 Safepoint::DeoptMode mode)
kasperl@chromium.orga5551262010-12-07 12:49:48 +000057 : codegen_(codegen),
58 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000059 deopt_mode_(mode) {}
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000060 virtual ~SafepointGenerator() {}
kasperl@chromium.orga5551262010-12-07 12:49:48 +000061
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000062 virtual void BeforeCall(int call_size) const V8_OVERRIDE {}
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000063
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000064 virtual void AfterCall() const V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000065 codegen_->RecordSafepoint(pointers_, deopt_mode_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000066 }
67
68 private:
69 LCodeGen* codegen_;
70 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000071 Safepoint::DeoptMode deopt_mode_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000072};
73
74
75#define __ masm()->
76
77bool LCodeGen::GenerateCode() {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000078 LPhase phase("Z_Code generation", chunk());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000079 ASSERT(is_unused());
80 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000081
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000082 // Open a frame scope to indicate that there is a frame on the stack. The
83 // MANUAL indicates that the scope shouldn't actually generate code to set up
84 // the frame (that is done in GeneratePrologue).
85 FrameScope frame_scope(masm_, StackFrame::MANUAL);
86
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000087 support_aligned_spilled_doubles_ = info()->IsOptimizing();
88
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000089 dynamic_frame_alignment_ = info()->IsOptimizing() &&
90 ((chunk()->num_double_slots() > 2 &&
91 !chunk()->graph()->is_recursive()) ||
92 !info()->osr_ast_id().IsNone());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000093
kasperl@chromium.orga5551262010-12-07 12:49:48 +000094 return GeneratePrologue() &&
95 GenerateBody() &&
96 GenerateDeferredCode() &&
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000097 GenerateJumpTable() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000098 GenerateSafepointTable();
99}
100
101
102void LCodeGen::FinishCode(Handle<Code> code) {
103 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000104 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000105 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000106 if (FLAG_weak_embedded_maps_in_optimized_code) {
107 RegisterDependentCodeForEmbeddedMaps(code);
108 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000109 PopulateDeoptimizationData(code);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000110 if (!info()->IsStub()) {
111 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
112 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000113 info()->CommitDependencies(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000114}
115
116
danno@chromium.org59400602013-08-13 17:09:37 +0000117void LCodeGen::Abort(BailoutReason reason) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000118 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000119 status_ = ABORTED;
120}
121
122
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000123#ifdef _MSC_VER
124void LCodeGen::MakeSureStackPagesMapped(int offset) {
125 const int kPageSize = 4 * KB;
126 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
127 __ mov(Operand(esp, offset), eax);
128 }
129}
130#endif
131
132
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000133bool LCodeGen::GeneratePrologue() {
134 ASSERT(is_generating());
135
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000136 if (info()->IsOptimizing()) {
137 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000138
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000139#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000140 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000141 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000142 __ int3();
143 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000144#endif
145
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000146 // Strict mode functions and builtins need to replace the receiver
147 // with undefined when called as functions (without an explicit
148 // receiver object). ecx is zero for method calls and non-zero for
149 // function calls.
150 if (!info_->is_classic_mode() || info_->is_native()) {
151 Label ok;
152 __ test(ecx, Operand(ecx));
153 __ j(zero, &ok, Label::kNear);
154 // +1 for return address.
155 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
156 __ mov(Operand(esp, receiver_offset),
157 Immediate(isolate()->factory()->undefined_value()));
158 __ bind(&ok);
159 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000160
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000161 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000162 // Move state of dynamic frame alignment into edx.
163 __ mov(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000164
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000165 Label do_not_pad, align_loop;
166 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
167 // Align esp + 4 to a multiple of 2 * kPointerSize.
168 __ test(esp, Immediate(kPointerSize));
169 __ j(not_zero, &do_not_pad, Label::kNear);
170 __ push(Immediate(0));
171 __ mov(ebx, esp);
172 __ mov(edx, Immediate(kAlignmentPaddingPushed));
173 // Copy arguments, receiver, and return address.
174 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000175
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000176 __ bind(&align_loop);
177 __ mov(eax, Operand(ebx, 1 * kPointerSize));
178 __ mov(Operand(ebx, 0), eax);
179 __ add(Operand(ebx), Immediate(kPointerSize));
180 __ dec(ecx);
181 __ j(not_zero, &align_loop, Label::kNear);
182 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
183 __ bind(&do_not_pad);
184 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000185 }
186
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000187 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000188 if (NeedsEagerFrame()) {
189 ASSERT(!frame_is_built_);
190 frame_is_built_ = true;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000191 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000192 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000193 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000194
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000195 if (info()->IsOptimizing() &&
196 dynamic_frame_alignment_ &&
197 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000198 __ test(esp, Immediate(kPointerSize));
danno@chromium.org59400602013-08-13 17:09:37 +0000199 __ Assert(zero, kFrameIsExpectedToBeAligned);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000200 }
201
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000202 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000203 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000204 ASSERT(slots != 0 || !info()->IsOptimizing());
205 if (slots > 0) {
206 if (slots == 1) {
207 if (dynamic_frame_alignment_) {
208 __ push(edx);
209 } else {
210 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000211 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000212 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000213 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000214 __ sub(Operand(esp), Immediate(slots * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000215#ifdef _MSC_VER
216 MakeSureStackPagesMapped(slots * kPointerSize);
217#endif
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000218 __ push(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000219 __ mov(Operand(eax), Immediate(slots));
220 Label loop;
221 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000222 __ mov(MemOperand(esp, eax, times_4, 0),
223 Immediate(kSlotsZapValue));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000224 __ dec(eax);
225 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000226 __ pop(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000227 } else {
228 __ sub(Operand(esp), Immediate(slots * kPointerSize));
229#ifdef _MSC_VER
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000230 MakeSureStackPagesMapped(slots * kPointerSize);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000231#endif
232 }
233
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000234 if (support_aligned_spilled_doubles_) {
235 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
236 // Store dynamic frame alignment state in the first local.
237 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
238 if (dynamic_frame_alignment_) {
239 __ mov(Operand(ebp, offset), edx);
240 } else {
241 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
242 }
243 }
244 }
245
246 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
247 Comment(";;; Save clobbered callee double registers");
ulan@chromium.org750145a2013-03-07 15:14:13 +0000248 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000249 int count = 0;
250 BitVector* doubles = chunk()->allocated_double_registers();
251 BitVector::Iterator save_iterator(doubles);
252 while (!save_iterator.Done()) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000253 __ movsd(MemOperand(esp, count * kDoubleSize),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000254 XMMRegister::FromAllocationIndex(save_iterator.Current()));
255 save_iterator.Advance();
256 count++;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000257 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000258 }
259 }
260
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000261 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000262 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000263 if (heap_slots > 0) {
264 Comment(";;; Allocate local context");
265 // Argument to NewContext is the function, which is still in edi.
266 __ push(edi);
267 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
268 FastNewContextStub stub(heap_slots);
269 __ CallStub(&stub);
270 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000271 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000272 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000273 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000274 // Context is returned in both eax and esi. It replaces the context
275 // passed to us. It's saved in the stack and kept live in esi.
276 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
277
278 // Copy parameters into context if necessary.
279 int num_parameters = scope()->num_parameters();
280 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000281 Variable* var = scope()->parameter(i);
282 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000283 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
284 (num_parameters - 1 - i) * kPointerSize;
285 // Load parameter from stack.
286 __ mov(eax, Operand(ebp, parameter_offset));
287 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000288 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000289 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000290 // Update the write barrier. This clobbers eax and ebx.
291 __ RecordWriteContextSlot(esi,
292 context_offset,
293 eax,
294 ebx,
295 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000296 }
297 }
298 Comment(";;; End allocate local context");
299 }
300
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000301 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000302 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000303 // We have not executed any compiled code yet, so esi still holds the
304 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000305 __ CallRuntime(Runtime::kTraceEnter, 0);
306 }
307 return !is_aborted();
308}
309
310
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000311void LCodeGen::GenerateOsrPrologue() {
312 // Generate the OSR entry prologue at the first unknown OSR value, or if there
313 // are none, at the OSR entrypoint instruction.
314 if (osr_pc_offset_ >= 0) return;
315
316 osr_pc_offset_ = masm()->pc_offset();
317
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000318 // Move state of dynamic frame alignment into edx.
319 __ mov(edx, Immediate(kNoAlignmentPadding));
320
321 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
322 Label do_not_pad, align_loop;
323 // Align ebp + 4 to a multiple of 2 * kPointerSize.
324 __ test(ebp, Immediate(kPointerSize));
325 __ j(zero, &do_not_pad, Label::kNear);
326 __ push(Immediate(0));
327 __ mov(ebx, esp);
328 __ mov(edx, Immediate(kAlignmentPaddingPushed));
329
330 // Move all parts of the frame over one word. The frame consists of:
331 // unoptimized frame slots, alignment state, context, frame pointer, return
332 // address, receiver, and the arguments.
333 __ mov(ecx, Immediate(scope()->num_parameters() +
334 5 + graph()->osr()->UnoptimizedFrameSlots()));
335
336 __ bind(&align_loop);
337 __ mov(eax, Operand(ebx, 1 * kPointerSize));
338 __ mov(Operand(ebx, 0), eax);
339 __ add(Operand(ebx), Immediate(kPointerSize));
340 __ dec(ecx);
341 __ j(not_zero, &align_loop, Label::kNear);
342 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
343 __ sub(Operand(ebp), Immediate(kPointerSize));
344 __ bind(&do_not_pad);
345 }
346
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000347 // Save the first local, which is overwritten by the alignment state.
348 Operand alignment_loc = MemOperand(ebp, -3 * kPointerSize);
349 __ push(alignment_loc);
350
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000351 // Set the dynamic frame alignment state.
352 __ mov(alignment_loc, edx);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000353
354 // Adjust the frame size, subsuming the unoptimized frame into the
355 // optimized frame.
356 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
357 ASSERT(slots >= 1);
358 __ sub(esp, Immediate((slots - 1) * kPointerSize));
359}
360
361
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000362void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
363 if (!CpuFeatures::IsSupported(SSE2)) FlushX87StackIfNecessary(instr);
364}
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000365
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000366
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000367void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
368 if (!CpuFeatures::IsSupported(SSE2)) {
369 if (instr->IsGoto()) {
370 x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr));
371 } else if (FLAG_debug_code && FLAG_enable_slow_asserts &&
372 !instr->IsGap() && !instr->IsReturn()) {
373 if (instr->ClobbersDoubleRegisters()) {
374 if (instr->HasDoubleRegisterResult()) {
375 ASSERT_EQ(1, x87_stack_.depth());
376 } else {
377 ASSERT_EQ(0, x87_stack_.depth());
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000378 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000379 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000380 __ VerifyX87StackDepth(x87_stack_.depth());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000381 }
382 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000383}
384
385
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000386bool LCodeGen::GenerateJumpTable() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000387 Label needs_frame;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000388 if (jump_table_.length() > 0) {
389 Comment(";;; -------------------- Jump table --------------------");
390 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000391 for (int i = 0; i < jump_table_.length(); i++) {
392 __ bind(&jump_table_[i].label);
393 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000394 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000395 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000396 if (id == Deoptimizer::kNotDeoptimizationEntry) {
397 Comment(";;; jump table entry %d.", i);
398 } else {
399 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
400 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000401 if (jump_table_[i].needs_frame) {
402 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
danno@chromium.org169691d2013-07-15 08:01:13 +0000403 if (needs_frame.is_bound()) {
404 __ jmp(&needs_frame);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000405 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000406 __ bind(&needs_frame);
407 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
408 // This variant of deopt can only be used with stubs. Since we don't
409 // have a function pointer to install in the stack frame that we're
410 // building, install a special marker there instead.
411 ASSERT(info()->IsStub());
412 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
413 // Push a PC inside the function so that the deopt code can find where
414 // the deopt comes from. It doesn't have to be the precise return
415 // address of a "calling" LAZY deopt, it only has to be somewhere
416 // inside the code body.
417 Label push_approx_pc;
418 __ call(&push_approx_pc);
419 __ bind(&push_approx_pc);
420 // Push the continuation which was stashed were the ebp should
421 // be. Replace it with the saved ebp.
422 __ push(MemOperand(esp, 3 * kPointerSize));
423 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
424 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
425 __ ret(0); // Call the continuation without clobbering registers.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000426 }
427 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000428 __ call(entry, RelocInfo::RUNTIME_ENTRY);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000429 }
430 }
431 return !is_aborted();
432}
433
434
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000435bool LCodeGen::GenerateDeferredCode() {
436 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000437 if (deferred_.length() > 0) {
438 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
439 LDeferredCode* code = deferred_[i];
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000440 X87Stack copy(code->x87_stack());
441 x87_stack_ = copy;
danno@chromium.org59400602013-08-13 17:09:37 +0000442
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000443 HValue* value =
444 instructions_->at(code->instruction_index())->hydrogen_value();
445 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000446
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000447 Comment(";;; <@%d,#%d> "
448 "-------------------- Deferred %s --------------------",
449 code->instruction_index(),
450 code->instr()->hydrogen_value()->id(),
451 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000452 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000453 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000454 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000455 ASSERT(!frame_is_built_);
456 ASSERT(info()->IsStub());
457 frame_is_built_ = true;
458 // Build the frame in such a way that esi isn't trashed.
459 __ push(ebp); // Caller's frame pointer.
460 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
461 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
462 __ lea(ebp, Operand(esp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000463 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000464 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000465 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000466 if (NeedsDeferredFrame()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000467 __ bind(code->done());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000468 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000469 ASSERT(frame_is_built_);
470 frame_is_built_ = false;
471 __ mov(esp, ebp);
472 __ pop(ebp);
473 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000474 __ jmp(code->exit());
475 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000476 }
477
478 // Deferred code is the last part of the instruction sequence. Mark
479 // the generated code as done unless we bailed out.
480 if (!is_aborted()) status_ = DONE;
481 return !is_aborted();
482}
483
484
485bool LCodeGen::GenerateSafepointTable() {
486 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000487 if (!info()->IsStub()) {
488 // For lazy deoptimization we need space to patch a call after every call.
489 // Ensure there is always space for such patching, even if the code ends
490 // in a call.
491 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
492 while (masm()->pc_offset() < target_offset) {
493 masm()->nop();
494 }
495 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000496 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000497 return !is_aborted();
498}
499
500
501Register LCodeGen::ToRegister(int index) const {
502 return Register::FromAllocationIndex(index);
503}
504
505
danno@chromium.org169691d2013-07-15 08:01:13 +0000506X87Register LCodeGen::ToX87Register(int index) const {
507 return X87Register::FromAllocationIndex(index);
508}
509
510
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000511XMMRegister LCodeGen::ToDoubleRegister(int index) const {
512 return XMMRegister::FromAllocationIndex(index);
513}
514
515
danno@chromium.org169691d2013-07-15 08:01:13 +0000516void LCodeGen::X87LoadForUsage(X87Register reg) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000517 ASSERT(x87_stack_.Contains(reg));
518 x87_stack_.Fxch(reg);
519 x87_stack_.pop();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000520}
521
522
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000523void LCodeGen::X87LoadForUsage(X87Register reg1, X87Register reg2) {
524 ASSERT(x87_stack_.Contains(reg1));
525 ASSERT(x87_stack_.Contains(reg2));
526 x87_stack_.Fxch(reg1, 1);
527 x87_stack_.Fxch(reg2);
528 x87_stack_.pop();
529 x87_stack_.pop();
530}
531
532
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000533void LCodeGen::X87Stack::Fxch(X87Register reg, int other_slot) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000534 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000535 ASSERT(Contains(reg) && stack_depth_ > other_slot);
536 int i = ArrayIndex(reg);
537 int st = st2idx(i);
danno@chromium.org169691d2013-07-15 08:01:13 +0000538 if (st != other_slot) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000539 int other_i = st2idx(other_slot);
540 X87Register other = stack_[other_i];
541 stack_[other_i] = reg;
542 stack_[i] = other;
danno@chromium.org169691d2013-07-15 08:01:13 +0000543 if (st == 0) {
544 __ fxch(other_slot);
545 } else if (other_slot == 0) {
546 __ fxch(st);
547 } else {
548 __ fxch(st);
549 __ fxch(other_slot);
550 __ fxch(st);
551 }
552 }
553}
554
555
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000556int LCodeGen::X87Stack::st2idx(int pos) {
557 return stack_depth_ - pos - 1;
danno@chromium.org169691d2013-07-15 08:01:13 +0000558}
559
560
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000561int LCodeGen::X87Stack::ArrayIndex(X87Register reg) {
562 for (int i = 0; i < stack_depth_; i++) {
563 if (stack_[i].is(reg)) return i;
danno@chromium.org169691d2013-07-15 08:01:13 +0000564 }
565 UNREACHABLE();
566 return -1;
567}
568
569
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000570bool LCodeGen::X87Stack::Contains(X87Register reg) {
571 for (int i = 0; i < stack_depth_; i++) {
572 if (stack_[i].is(reg)) return true;
danno@chromium.org169691d2013-07-15 08:01:13 +0000573 }
574 return false;
575}
576
577
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000578void LCodeGen::X87Stack::Free(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000579 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000580 ASSERT(Contains(reg));
581 int i = ArrayIndex(reg);
582 int st = st2idx(i);
danno@chromium.org169691d2013-07-15 08:01:13 +0000583 if (st > 0) {
584 // keep track of how fstp(i) changes the order of elements
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000585 int tos_i = st2idx(0);
586 stack_[i] = stack_[tos_i];
danno@chromium.org169691d2013-07-15 08:01:13 +0000587 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000588 pop();
danno@chromium.org169691d2013-07-15 08:01:13 +0000589 __ fstp(st);
590}
591
592
593void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000594 if (x87_stack_.Contains(dst)) {
595 x87_stack_.Fxch(dst);
danno@chromium.org169691d2013-07-15 08:01:13 +0000596 __ fstp(0);
597 } else {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000598 x87_stack_.push(dst);
danno@chromium.org169691d2013-07-15 08:01:13 +0000599 }
600 X87Fld(src, opts);
601}
602
603
604void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000605 ASSERT(!src.is_reg_only());
606 switch (opts) {
607 case kX87DoubleOperand:
608 __ fld_d(src);
609 break;
610 case kX87FloatOperand:
611 __ fld_s(src);
612 break;
613 case kX87IntOperand:
614 __ fild_s(src);
615 break;
616 default:
617 UNREACHABLE();
danno@chromium.org169691d2013-07-15 08:01:13 +0000618 }
619}
620
621
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000622void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) {
623 ASSERT(!dst.is_reg_only());
624 x87_stack_.Fxch(src);
625 switch (opts) {
626 case kX87DoubleOperand:
627 __ fst_d(dst);
628 break;
629 case kX87IntOperand:
630 __ fist_s(dst);
631 break;
632 default:
633 UNREACHABLE();
634 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000635}
636
637
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000638void LCodeGen::X87Stack::PrepareToWrite(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000639 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000640 if (Contains(reg)) {
641 Free(reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000642 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000643 // Mark this register as the next register to write to
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000644 stack_[stack_depth_] = reg;
danno@chromium.org169691d2013-07-15 08:01:13 +0000645}
646
647
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000648void LCodeGen::X87Stack::CommitWrite(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000649 ASSERT(is_mutable_);
danno@chromium.org169691d2013-07-15 08:01:13 +0000650 // Assert the reg is prepared to write, but not on the virtual stack yet
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000651 ASSERT(!Contains(reg) && stack_[stack_depth_].is(reg) &&
652 stack_depth_ < X87Register::kNumAllocatableRegisters);
653 stack_depth_++;
danno@chromium.org169691d2013-07-15 08:01:13 +0000654}
655
656
657void LCodeGen::X87PrepareBinaryOp(
658 X87Register left, X87Register right, X87Register result) {
659 // You need to use DefineSameAsFirst for x87 instructions
660 ASSERT(result.is(left));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000661 x87_stack_.Fxch(right, 1);
662 x87_stack_.Fxch(left);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000663}
664
665
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000666void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) {
667 if (stack_depth_ > 0 && instr->ClobbersDoubleRegisters()) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000668 bool double_inputs = instr->HasDoubleRegisterInput();
669
670 // Flush stack from tos down, since FreeX87() will mess with tos
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000671 for (int i = stack_depth_-1; i >= 0; i--) {
672 X87Register reg = stack_[i];
danno@chromium.org169691d2013-07-15 08:01:13 +0000673 // Skip registers which contain the inputs for the next instruction
674 // when flushing the stack
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000675 if (double_inputs && instr->IsDoubleInput(reg, cgen)) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000676 continue;
677 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000678 Free(reg);
679 if (i < stack_depth_-1) i++;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000680 }
681 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000682 if (instr->IsReturn()) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000683 while (stack_depth_ > 0) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000684 __ fstp(0);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000685 stack_depth_--;
danno@chromium.org169691d2013-07-15 08:01:13 +0000686 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000687 if (FLAG_debug_code && FLAG_enable_slow_asserts) __ VerifyX87StackDepth(0);
688 }
689}
690
691
692void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr) {
693 ASSERT(stack_depth_ <= 1);
694 // If ever used for new stubs producing two pairs of doubles joined into two
695 // phis this assert hits. That situation is not handled, since the two stacks
696 // might have st0 and st1 swapped.
697 if (current_block_id + 1 != goto_instr->block_id()) {
698 // If we have a value on the x87 stack on leaving a block, it must be a
699 // phi input. If the next block we compile is not the join block, we have
700 // to discard the stack state.
701 stack_depth_ = 0;
danno@chromium.org169691d2013-07-15 08:01:13 +0000702 }
703}
704
705
706void LCodeGen::EmitFlushX87ForDeopt() {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000707 // The deoptimizer does not support X87 Registers. But as long as we
708 // deopt from a stub its not a problem, since we will re-materialize the
709 // original stub inputs, which can't be double registers.
710 ASSERT(info()->IsStub());
711 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
712 __ pushfd();
713 __ VerifyX87StackDepth(x87_stack_.depth());
714 __ popfd();
715 }
716 for (int i = 0; i < x87_stack_.depth(); i++) __ fstp(0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000717}
718
719
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000720Register LCodeGen::ToRegister(LOperand* op) const {
721 ASSERT(op->IsRegister());
722 return ToRegister(op->index());
723}
724
725
danno@chromium.org169691d2013-07-15 08:01:13 +0000726X87Register LCodeGen::ToX87Register(LOperand* op) const {
727 ASSERT(op->IsDoubleRegister());
728 return ToX87Register(op->index());
729}
730
731
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000732XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
733 ASSERT(op->IsDoubleRegister());
734 return ToDoubleRegister(op->index());
735}
736
737
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000738int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
739 return ToRepresentation(op, Representation::Integer32());
740}
741
742
743int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
744 const Representation& r) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000745 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000746 int32_t value = constant->Integer32Value();
747 if (r.IsInteger32()) return value;
748 ASSERT(r.IsSmiOrTagged());
749 return reinterpret_cast<int32_t>(Smi::FromInt(value));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000750}
751
752
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000753Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000754 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000755 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000756 return constant->handle(isolate());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000757}
758
759
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000760double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000761 HConstant* constant = chunk_->LookupConstant(op);
762 ASSERT(constant->HasDoubleValue());
763 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764}
765
766
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000767ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
768 HConstant* constant = chunk_->LookupConstant(op);
769 ASSERT(constant->HasExternalReferenceValue());
770 return constant->ExternalReferenceValue();
771}
772
773
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000774bool LCodeGen::IsInteger32(LConstantOperand* op) const {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000775 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776}
777
778
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000779bool LCodeGen::IsSmi(LConstantOperand* op) const {
780 return chunk_->LookupLiteralRepresentation(op).IsSmi();
781}
782
783
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000784Operand LCodeGen::ToOperand(LOperand* op) const {
785 if (op->IsRegister()) return Operand(ToRegister(op));
786 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
787 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000788 return Operand(ebp, StackSlotOffset(op->index()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000789}
790
791
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000792Operand LCodeGen::HighOperand(LOperand* op) {
793 ASSERT(op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000794 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000795}
796
797
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000798void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000799 Translation* translation) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000800 if (environment == NULL) return;
801
802 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000803 int translation_size = environment->translation_size();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000804 // The output frame height does not include the parameters.
805 int height = translation_size - environment->parameter_count();
806
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000807 WriteTranslation(environment->outer(), translation);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000808 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000809 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000810 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000811 ? DefineDeoptimizationLiteral(environment->closure())
812 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000813 switch (environment->frame_type()) {
814 case JS_FUNCTION:
815 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
816 break;
817 case JS_CONSTRUCT:
818 translation->BeginConstructStubFrame(closure_id, translation_size);
819 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000820 case JS_GETTER:
821 ASSERT(translation_size == 1);
822 ASSERT(height == 0);
823 translation->BeginGetterStubFrame(closure_id);
824 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000825 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000826 ASSERT(translation_size == 2);
827 ASSERT(height == 0);
828 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000829 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000830 case ARGUMENTS_ADAPTOR:
831 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
832 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000833 case STUB:
834 translation->BeginCompiledStubFrame();
835 break;
836 default:
837 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000838 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000839
danno@chromium.org59400602013-08-13 17:09:37 +0000840 int object_index = 0;
841 int dematerialized_index = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000842 for (int i = 0; i < translation_size; ++i) {
843 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000844 AddToTranslation(environment,
845 translation,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000846 value,
847 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000848 environment->HasUint32ValueAt(i),
849 &object_index,
850 &dematerialized_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000851 }
852}
853
854
danno@chromium.org59400602013-08-13 17:09:37 +0000855void LCodeGen::AddToTranslation(LEnvironment* environment,
856 Translation* translation,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000857 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000858 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000859 bool is_uint32,
860 int* object_index_pointer,
861 int* dematerialized_index_pointer) {
862 if (op == LEnvironment::materialization_marker()) {
863 int object_index = (*object_index_pointer)++;
864 if (environment->ObjectIsDuplicateAt(object_index)) {
865 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
866 translation->DuplicateObject(dupe_of);
867 return;
868 }
869 int object_length = environment->ObjectLengthAt(object_index);
870 if (environment->ObjectIsArgumentsAt(object_index)) {
871 translation->BeginArgumentsObject(object_length);
872 } else {
873 translation->BeginCapturedObject(object_length);
874 }
875 int dematerialized_index = *dematerialized_index_pointer;
876 int env_offset = environment->translation_size() + dematerialized_index;
877 *dematerialized_index_pointer += object_length;
878 for (int i = 0; i < object_length; ++i) {
879 LOperand* value = environment->values()->at(env_offset + i);
880 AddToTranslation(environment,
881 translation,
882 value,
883 environment->HasTaggedValueAt(env_offset + i),
884 environment->HasUint32ValueAt(env_offset + i),
885 object_index_pointer,
886 dematerialized_index_pointer);
887 }
888 return;
889 }
890
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000891 if (op->IsStackSlot()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000892 if (is_tagged) {
893 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000894 } else if (is_uint32) {
895 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000896 } else {
897 translation->StoreInt32StackSlot(op->index());
898 }
899 } else if (op->IsDoubleStackSlot()) {
900 translation->StoreDoubleStackSlot(op->index());
901 } else if (op->IsArgument()) {
902 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000903 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000904 translation->StoreStackSlot(src_index);
905 } else if (op->IsRegister()) {
906 Register reg = ToRegister(op);
907 if (is_tagged) {
908 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000909 } else if (is_uint32) {
910 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000911 } else {
912 translation->StoreInt32Register(reg);
913 }
914 } else if (op->IsDoubleRegister()) {
915 XMMRegister reg = ToDoubleRegister(op);
916 translation->StoreDoubleRegister(reg);
917 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000918 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000919 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000920 translation->StoreLiteral(src_index);
921 } else {
922 UNREACHABLE();
923 }
924}
925
926
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000927void LCodeGen::CallCodeGeneric(Handle<Code> code,
928 RelocInfo::Mode mode,
929 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000930 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000931 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000932 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000933 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000934
935 // Signal that we don't inline smi code before these stubs in the
936 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000937 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000938 code->kind() == Code::COMPARE_IC) {
939 __ nop();
940 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000941}
942
943
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000944void LCodeGen::CallCode(Handle<Code> code,
945 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000946 LInstruction* instr) {
947 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000948}
949
950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000952 int argc,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000953 LInstruction* instr,
954 SaveFPRegsMode save_doubles) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000955 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000956 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000957
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000958 __ CallRuntime(fun, argc, save_doubles);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000959
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000960 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000961
962 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000963}
964
965
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000966void LCodeGen::LoadContextFromDeferred(LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000967 if (context->IsRegister()) {
968 if (!ToRegister(context).is(esi)) {
969 __ mov(esi, ToRegister(context));
970 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000971 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000972 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000973 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000974 HConstant* constant =
975 chunk_->LookupConstant(LConstantOperand::cast(context));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000976 __ LoadObject(esi, Handle<Object>::cast(constant->handle(isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000977 } else {
978 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000979 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000980}
981
982void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
983 int argc,
984 LInstruction* instr,
985 LOperand* context) {
986 LoadContextFromDeferred(context);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000987
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000988 __ CallRuntimeSaveDoubles(id);
989 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000990 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000991
992 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000993}
994
995
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000996void LCodeGen::RegisterEnvironmentForDeoptimization(
997 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000998 if (!environment->HasBeenRegistered()) {
999 // Physical stack frame layout:
1000 // -x ............. -4 0 ..................................... y
1001 // [incoming arguments] [spill slots] [pushed outgoing arguments]
1002
1003 // Layout of the environment:
1004 // 0 ..................................................... size-1
1005 // [parameters] [locals] [expression stack including arguments]
1006
1007 // Layout of the translation:
1008 // 0 ........................................................ size - 1 + 4
1009 // [expression stack including arguments] [locals] [4 words] [parameters]
1010 // |>------------ translation_size ------------<|
1011
1012 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001013 int jsframe_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001014 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
1015 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +00001016 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001017 ++jsframe_count;
1018 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001019 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001020 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001021 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001022 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001023 int pc_offset = masm()->pc_offset();
1024 environment->Register(deoptimization_index,
1025 translation.index(),
1026 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001027 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001028 }
1029}
1030
1031
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001032void LCodeGen::DeoptimizeIf(Condition cc,
1033 LEnvironment* environment,
1034 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001035 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001036 ASSERT(environment->HasBeenRegistered());
1037 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001038 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001039 Address entry =
1040 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001041 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +00001042 Abort(kBailoutWasNotPrepared);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001043 return;
1044 }
1045
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001046 if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001047 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001048 Label no_deopt;
1049 __ pushfd();
1050 __ push(eax);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001051 __ mov(eax, Operand::StaticVariable(count));
1052 __ sub(eax, Immediate(1));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001053 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001054 if (FLAG_trap_on_deopt) __ int3();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001055 __ mov(eax, Immediate(FLAG_deopt_every_n_times));
1056 __ mov(Operand::StaticVariable(count), eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057 __ pop(eax);
1058 __ popfd();
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001059 ASSERT(frame_is_built_);
1060 __ call(entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001061 __ bind(&no_deopt);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001062 __ mov(Operand::StaticVariable(count), eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001063 __ pop(eax);
1064 __ popfd();
1065 }
1066
danno@chromium.org169691d2013-07-15 08:01:13 +00001067 // Before Instructions which can deopt, we normally flush the x87 stack. But
1068 // we can have inputs or outputs of the current instruction on the stack,
1069 // thus we need to flush them here from the physical stack to leave it in a
1070 // consistent state.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001071 if (x87_stack_.depth() > 0) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001072 Label done;
1073 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
1074 EmitFlushX87ForDeopt();
1075 __ bind(&done);
1076 }
1077
danno@chromium.org59400602013-08-13 17:09:37 +00001078 if (info()->ShouldTrapOnDeopt()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001079 Label done;
danno@chromium.org169691d2013-07-15 08:01:13 +00001080 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001081 __ int3();
1082 __ bind(&done);
1083 }
1084
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001085 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001086 if (cc == no_condition && frame_is_built_) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001087 __ call(entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001088 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001089 // We often have several deopts to the same entry, reuse the last
1090 // jump entry if this is the case.
1091 if (jump_table_.is_empty() ||
1092 jump_table_.last().address != entry ||
1093 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001094 jump_table_.last().bailout_type != bailout_type) {
1095 Deoptimizer::JumpTableEntry table_entry(entry,
1096 bailout_type,
1097 !frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001098 jump_table_.Add(table_entry, zone());
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001099 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001100 if (cc == no_condition) {
1101 __ jmp(&jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001102 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001103 __ j(cc, &jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001104 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001105 }
1106}
1107
1108
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001109void LCodeGen::DeoptimizeIf(Condition cc,
1110 LEnvironment* environment) {
1111 Deoptimizer::BailoutType bailout_type = info()->IsStub()
1112 ? Deoptimizer::LAZY
1113 : Deoptimizer::EAGER;
1114 DeoptimizeIf(cc, environment, bailout_type);
1115}
1116
1117
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001118void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
1119 ZoneList<Handle<Map> > maps(1, zone());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001120 ZoneList<Handle<JSObject> > objects(1, zone());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001121 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
1122 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001123 if (Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_object())) {
1124 if (it.rinfo()->target_object()->IsMap()) {
1125 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001126 maps.Add(map, zone());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001127 } else if (it.rinfo()->target_object()->IsJSObject()) {
1128 Handle<JSObject> object(JSObject::cast(it.rinfo()->target_object()));
1129 objects.Add(object, zone());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001130 }
1131 }
1132 }
1133#ifdef VERIFY_HEAP
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001134 // This disables verification of weak embedded objects after full GC.
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001135 // AddDependentCode can cause a GC, which would observe the state where
1136 // this code is not yet in the depended code lists of the embedded maps.
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001137 NoWeakObjectVerificationScope disable_verification_of_embedded_objects;
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001138#endif
1139 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001140 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001141 }
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00001142 for (int i = 0; i < objects.length(); i++) {
1143 AddWeakObjectToCodeDependency(isolate()->heap(), objects.at(i), code);
1144 }
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +00001145}
1146
1147
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001148void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
1149 int length = deoptimizations_.length();
1150 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001151 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001153
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00001154 Handle<ByteArray> translations =
1155 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001156 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001157 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
1158
1159 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001161 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001162 for (int i = 0; i < deoptimization_literals_.length(); i++) {
1163 literals->set(i, *deoptimization_literals_[i]);
1164 }
1165 data->SetLiteralArray(*literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001166 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001167
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001168 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001169 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
1170
1171 // Populate the deoptimization entries.
1172 for (int i = 0; i < length; i++) {
1173 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001174 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001175 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
1176 data->SetArgumentsStackHeight(i,
1177 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001178 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001179 }
1180 code->set_deoptimization_data(*data);
1181}
1182
1183
1184int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
1185 int result = deoptimization_literals_.length();
1186 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
1187 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
1188 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001189 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001190 return result;
1191}
1192
1193
1194void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
1195 ASSERT(deoptimization_literals_.length() == 0);
1196
1197 const ZoneList<Handle<JSFunction> >* inlined_closures =
1198 chunk()->inlined_closures();
1199
1200 for (int i = 0, length = inlined_closures->length();
1201 i < length;
1202 i++) {
1203 DefineDeoptimizationLiteral(inlined_closures->at(i));
1204 }
1205
1206 inlined_function_count_ = deoptimization_literals_.length();
1207}
1208
1209
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001210void LCodeGen::RecordSafepointWithLazyDeopt(
1211 LInstruction* instr, SafepointMode safepoint_mode) {
1212 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
1213 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
1214 } else {
1215 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
1216 RecordSafepointWithRegisters(
1217 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
1218 }
1219}
1220
1221
ager@chromium.org378b34e2011-01-28 08:04:38 +00001222void LCodeGen::RecordSafepoint(
1223 LPointerMap* pointers,
1224 Safepoint::Kind kind,
1225 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001226 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001227 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001228 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001229 Safepoint safepoint =
1230 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001231 for (int i = 0; i < operands->length(); i++) {
1232 LOperand* pointer = operands->at(i);
1233 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001234 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +00001235 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001236 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001237 }
1238 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00001239}
1240
1241
1242void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001243 Safepoint::DeoptMode mode) {
1244 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001245}
1246
1247
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001248void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001249 LPointerMap empty_pointers(zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001250 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001251}
1252
1253
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001254void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1255 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001256 Safepoint::DeoptMode mode) {
1257 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001258}
1259
1260
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001261void LCodeGen::RecordAndWritePosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001262 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001263 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001264 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +00001265}
1266
1267
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001268static const char* LabelType(LLabel* label) {
1269 if (label->is_loop_header()) return " (loop header)";
1270 if (label->is_osr_entry()) return " (OSR entry)";
1271 return "";
1272}
1273
1274
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001275void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001276 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
1277 current_instruction_,
1278 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001279 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001280 LabelType(label));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001281 __ bind(label->label());
1282 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001283 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001284}
1285
1286
1287void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001288 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001289}
1290
1291
1292void LCodeGen::DoGap(LGap* gap) {
1293 for (int i = LGap::FIRST_INNER_POSITION;
1294 i <= LGap::LAST_INNER_POSITION;
1295 i++) {
1296 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1297 LParallelMove* move = gap->GetParallelMove(inner_pos);
1298 if (move != NULL) DoParallelMove(move);
1299 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001300}
1301
1302
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001303void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1304 DoGap(instr);
1305}
1306
1307
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001308void LCodeGen::DoParameter(LParameter* instr) {
1309 // Nothing to do.
1310}
1311
1312
1313void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001314 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001315 ASSERT(ToRegister(instr->result()).is(eax));
1316 switch (instr->hydrogen()->major_key()) {
1317 case CodeStub::RegExpConstructResult: {
1318 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001319 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001320 break;
1321 }
1322 case CodeStub::RegExpExec: {
1323 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001324 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001325 break;
1326 }
1327 case CodeStub::SubString: {
1328 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001329 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001330 break;
1331 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001332 case CodeStub::StringCompare: {
1333 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001334 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001335 break;
1336 }
1337 case CodeStub::TranscendentalCache: {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001338 TranscendentalCacheStub stub(instr->transcendental_type(),
1339 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001340 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001341 break;
1342 }
1343 default:
1344 UNREACHABLE();
1345 }
1346}
1347
1348
1349void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001350 GenerateOsrPrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001351}
1352
1353
1354void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001355 HMod* hmod = instr->hydrogen();
1356 HValue* left = hmod->left();
1357 HValue* right = hmod->right();
1358 if (hmod->HasPowerOf2Divisor()) {
1359 // TODO(svenpanne) We should really do the strength reduction on the
1360 // Hydrogen level.
1361 Register left_reg = ToRegister(instr->left());
1362 ASSERT(left_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001363
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001364 // Note: The code below even works when right contains kMinInt.
1365 int32_t divisor = Abs(right->GetInteger32Constant());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001366
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001367 Label left_is_not_negative, done;
1368 if (left->CanBeNegative()) {
1369 __ test(left_reg, Operand(left_reg));
1370 __ j(not_sign, &left_is_not_negative, Label::kNear);
1371 __ neg(left_reg);
1372 __ and_(left_reg, divisor - 1);
1373 __ neg(left_reg);
1374 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1375 DeoptimizeIf(zero, instr->environment());
1376 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001377 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001378 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001379
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001380 __ bind(&left_is_not_negative);
1381 __ and_(left_reg, divisor - 1);
1382 __ bind(&done);
1383
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001384 } else if (hmod->fixed_right_arg().has_value) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001385 Register left_reg = ToRegister(instr->left());
1386 ASSERT(left_reg.is(ToRegister(instr->result())));
1387 Register right_reg = ToRegister(instr->right());
1388
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001389 int32_t divisor = hmod->fixed_right_arg().value;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001390 ASSERT(IsPowerOf2(divisor));
1391
1392 // Check if our assumption of a fixed right operand still holds.
1393 __ cmp(right_reg, Immediate(divisor));
1394 DeoptimizeIf(not_equal, instr->environment());
1395
1396 Label left_is_not_negative, done;
1397 if (left->CanBeNegative()) {
1398 __ test(left_reg, Operand(left_reg));
1399 __ j(not_sign, &left_is_not_negative, Label::kNear);
1400 __ neg(left_reg);
1401 __ and_(left_reg, divisor - 1);
1402 __ neg(left_reg);
1403 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1404 DeoptimizeIf(zero, instr->environment());
1405 }
1406 __ jmp(&done, Label::kNear);
1407 }
1408
1409 __ bind(&left_is_not_negative);
1410 __ and_(left_reg, divisor - 1);
1411 __ bind(&done);
1412
1413 } else {
1414 Register left_reg = ToRegister(instr->left());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001415 ASSERT(left_reg.is(eax));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001416 Register right_reg = ToRegister(instr->right());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001417 ASSERT(!right_reg.is(eax));
1418 ASSERT(!right_reg.is(edx));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001419 Register result_reg = ToRegister(instr->result());
1420 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001421
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001422 Label done;
1423 // Check for x % 0, idiv would signal a divide error. We have to
1424 // deopt in this case because we can't return a NaN.
1425 if (right->CanBeZero()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001426 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001427 DeoptimizeIf(zero, instr->environment());
1428 }
1429
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001430 // Check for kMinInt % -1, idiv would signal a divide error. We
1431 // have to deopt if we care about -0, because we can't return that.
1432 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1433 Label no_overflow_possible;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001434 __ cmp(left_reg, kMinInt);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001435 __ j(not_equal, &no_overflow_possible, Label::kNear);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001436 __ cmp(right_reg, -1);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001437 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1438 DeoptimizeIf(equal, instr->environment());
1439 } else {
1440 __ j(not_equal, &no_overflow_possible, Label::kNear);
1441 __ Set(result_reg, Immediate(0));
1442 __ jmp(&done, Label::kNear);
1443 }
1444 __ bind(&no_overflow_possible);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001445 }
1446
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001447 // Sign extend dividend in eax into edx:eax.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001448 __ cdq();
1449
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001450 // If we care about -0, test if the dividend is <0 and the result is 0.
1451 if (left->CanBeNegative() &&
1452 hmod->CanBeZero() &&
1453 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001454 Label positive_left;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001455 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001456 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001457 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001458 __ test(result_reg, Operand(result_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001459 DeoptimizeIf(zero, instr->environment());
1460 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001461 __ bind(&positive_left);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001462 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001463 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001464 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001465 }
1466}
1467
1468
1469void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001470 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001471 Register dividend = ToRegister(instr->left());
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001472 int32_t divisor = instr->hydrogen()->right()->GetInteger32Constant();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001473 int32_t test_value = 0;
1474 int32_t power = 0;
1475
1476 if (divisor > 0) {
1477 test_value = divisor - 1;
1478 power = WhichPowerOf2(divisor);
1479 } else {
1480 // Check for (0 / -x) that will produce negative zero.
1481 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1482 __ test(dividend, Operand(dividend));
1483 DeoptimizeIf(zero, instr->environment());
1484 }
1485 // Check for (kMinInt / -1).
1486 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1487 __ cmp(dividend, kMinInt);
1488 DeoptimizeIf(zero, instr->environment());
1489 }
1490 test_value = - divisor - 1;
1491 power = WhichPowerOf2(-divisor);
1492 }
1493
1494 if (test_value != 0) {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001495 if (instr->hydrogen()->CheckFlag(
1496 HInstruction::kAllUsesTruncatingToInt32)) {
1497 Label done, negative;
1498 __ cmp(dividend, 0);
1499 __ j(less, &negative, Label::kNear);
1500 __ sar(dividend, power);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001501 if (divisor < 0) __ neg(dividend);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001502 __ jmp(&done, Label::kNear);
1503
1504 __ bind(&negative);
1505 __ neg(dividend);
1506 __ sar(dividend, power);
1507 if (divisor > 0) __ neg(dividend);
1508 __ bind(&done);
1509 return; // Don't fall through to "__ neg" below.
1510 } else {
1511 // Deoptimize if remainder is not 0.
1512 __ test(dividend, Immediate(test_value));
1513 DeoptimizeIf(not_zero, instr->environment());
1514 __ sar(dividend, power);
1515 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001516 }
1517
1518 if (divisor < 0) __ neg(dividend);
1519
1520 return;
1521 }
1522
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001523 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001524 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001525 ASSERT(ToRegister(instr->left()).is(eax));
1526 ASSERT(!ToRegister(instr->right()).is(eax));
1527 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001528
1529 Register left_reg = eax;
1530
1531 // Check for x / 0.
1532 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001533 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001534 __ test(right_reg, ToOperand(right));
1535 DeoptimizeIf(zero, instr->environment());
1536 }
1537
1538 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001539 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001540 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001541 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001542 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543 __ test(right_reg, ToOperand(right));
1544 DeoptimizeIf(sign, instr->environment());
1545 __ bind(&left_not_zero);
1546 }
1547
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001548 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001549 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001550 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001551 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001552 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001553 __ cmp(right_reg, -1);
1554 DeoptimizeIf(zero, instr->environment());
1555 __ bind(&left_not_min_int);
1556 }
1557
1558 // Sign extend to edx.
1559 __ cdq();
1560 __ idiv(right_reg);
1561
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001562 if (instr->is_flooring()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001563 Label done;
1564 __ test(edx, edx);
1565 __ j(zero, &done, Label::kNear);
1566 __ xor_(edx, right_reg);
1567 __ sar(edx, 31);
1568 __ add(eax, edx);
1569 __ bind(&done);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001570 } else if (!instr->hydrogen()->CheckFlag(
1571 HInstruction::kAllUsesTruncatingToInt32)) {
1572 // Deoptimize if remainder is not 0.
1573 __ test(edx, Operand(edx));
1574 DeoptimizeIf(not_zero, instr->environment());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001575 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001576}
1577
1578
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001579void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001580 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001581
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001582 Register dividend = ToRegister(instr->left());
1583 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001584 Register result = ToRegister(instr->result());
1585
1586 switch (divisor) {
1587 case 0:
1588 DeoptimizeIf(no_condition, instr->environment());
1589 return;
1590
1591 case 1:
1592 __ Move(result, dividend);
1593 return;
1594
1595 case -1:
1596 __ Move(result, dividend);
1597 __ neg(result);
1598 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1599 DeoptimizeIf(zero, instr->environment());
1600 }
1601 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1602 DeoptimizeIf(overflow, instr->environment());
1603 }
1604 return;
1605 }
1606
1607 uint32_t divisor_abs = abs(divisor);
1608 if (IsPowerOf2(divisor_abs)) {
1609 int32_t power = WhichPowerOf2(divisor_abs);
1610 if (divisor < 0) {
1611 // Input[dividend] is clobbered.
1612 // The sequence is tedious because neg(dividend) might overflow.
1613 __ mov(result, dividend);
1614 __ sar(dividend, 31);
1615 __ neg(result);
1616 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1617 DeoptimizeIf(zero, instr->environment());
1618 }
1619 __ shl(dividend, 32 - power);
1620 __ sar(result, power);
1621 __ not_(dividend);
1622 // Clear result.sign if dividend.sign is set.
1623 __ and_(result, dividend);
1624 } else {
1625 __ Move(result, dividend);
1626 __ sar(result, power);
1627 }
1628 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001629 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001630 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001631 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001632
1633 // Find b which: 2^b < divisor_abs < 2^(b+1).
1634 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1635 unsigned shift = 32 + b; // Precision +1bit (effectively).
1636 double multiplier_f =
1637 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1638 int64_t multiplier;
1639 if (multiplier_f - floor(multiplier_f) < 0.5) {
1640 multiplier = static_cast<int64_t>(floor(multiplier_f));
1641 } else {
1642 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1643 }
1644 // The multiplier is a uint32.
1645 ASSERT(multiplier > 0 &&
1646 multiplier < (static_cast<int64_t>(1) << 32));
1647 __ mov(scratch, dividend);
1648 if (divisor < 0 &&
1649 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1650 __ test(dividend, dividend);
1651 DeoptimizeIf(zero, instr->environment());
1652 }
1653 __ mov(edx, static_cast<int32_t>(multiplier));
1654 __ imul(edx);
1655 if (static_cast<int32_t>(multiplier) < 0) {
1656 __ add(edx, scratch);
1657 }
1658 Register reg_lo = eax;
1659 Register reg_byte_scratch = scratch;
1660 if (!reg_byte_scratch.is_byte_register()) {
1661 __ xchg(reg_lo, reg_byte_scratch);
1662 reg_lo = scratch;
1663 reg_byte_scratch = eax;
1664 }
1665 if (divisor < 0) {
1666 __ xor_(reg_byte_scratch, reg_byte_scratch);
1667 __ cmp(reg_lo, 0x40000000);
1668 __ setcc(above, reg_byte_scratch);
1669 __ neg(edx);
1670 __ sub(edx, reg_byte_scratch);
1671 } else {
1672 __ xor_(reg_byte_scratch, reg_byte_scratch);
1673 __ cmp(reg_lo, 0xC0000000);
1674 __ setcc(above_equal, reg_byte_scratch);
1675 __ add(edx, reg_byte_scratch);
1676 }
1677 __ sar(edx, shift - 32);
1678 }
1679}
1680
1681
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001682void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001683 Register left = ToRegister(instr->left());
1684 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685
1686 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001687 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001688 }
1689
1690 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001691 // Try strength reductions on the multiplication.
1692 // All replacement instructions are at most as long as the imul
1693 // and have better latency.
1694 int constant = ToInteger32(LConstantOperand::cast(right));
1695 if (constant == -1) {
1696 __ neg(left);
1697 } else if (constant == 0) {
1698 __ xor_(left, Operand(left));
1699 } else if (constant == 2) {
1700 __ add(left, Operand(left));
1701 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1702 // If we know that the multiplication can't overflow, it's safe to
1703 // use instructions that don't set the overflow flag for the
1704 // multiplication.
1705 switch (constant) {
1706 case 1:
1707 // Do nothing.
1708 break;
1709 case 3:
1710 __ lea(left, Operand(left, left, times_2, 0));
1711 break;
1712 case 4:
1713 __ shl(left, 2);
1714 break;
1715 case 5:
1716 __ lea(left, Operand(left, left, times_4, 0));
1717 break;
1718 case 8:
1719 __ shl(left, 3);
1720 break;
1721 case 9:
1722 __ lea(left, Operand(left, left, times_8, 0));
1723 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001724 case 16:
1725 __ shl(left, 4);
1726 break;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001727 default:
1728 __ imul(left, left, constant);
1729 break;
1730 }
1731 } else {
1732 __ imul(left, left, constant);
1733 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001734 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001735 if (instr->hydrogen()->representation().IsSmi()) {
1736 __ SmiUntag(left);
1737 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001738 __ imul(left, ToOperand(right));
1739 }
1740
1741 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1742 DeoptimizeIf(overflow, instr->environment());
1743 }
1744
1745 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1746 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001747 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001748 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001749 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001750 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001751 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001752 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001753 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1754 __ cmp(ToRegister(instr->temp()), Immediate(0));
1755 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 }
1757 } else {
1758 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001759 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001760 DeoptimizeIf(sign, instr->environment());
1761 }
1762 __ bind(&done);
1763 }
1764}
1765
1766
1767void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001768 LOperand* left = instr->left();
1769 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001770 ASSERT(left->Equals(instr->result()));
1771 ASSERT(left->IsRegister());
1772
1773 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001774 int32_t right_operand =
1775 ToRepresentation(LConstantOperand::cast(right),
1776 instr->hydrogen()->representation());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001777 switch (instr->op()) {
1778 case Token::BIT_AND:
1779 __ and_(ToRegister(left), right_operand);
1780 break;
1781 case Token::BIT_OR:
1782 __ or_(ToRegister(left), right_operand);
1783 break;
1784 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001785 if (right_operand == int32_t(~0)) {
1786 __ not_(ToRegister(left));
1787 } else {
1788 __ xor_(ToRegister(left), right_operand);
1789 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001790 break;
1791 default:
1792 UNREACHABLE();
1793 break;
1794 }
1795 } else {
1796 switch (instr->op()) {
1797 case Token::BIT_AND:
1798 __ and_(ToRegister(left), ToOperand(right));
1799 break;
1800 case Token::BIT_OR:
1801 __ or_(ToRegister(left), ToOperand(right));
1802 break;
1803 case Token::BIT_XOR:
1804 __ xor_(ToRegister(left), ToOperand(right));
1805 break;
1806 default:
1807 UNREACHABLE();
1808 break;
1809 }
1810 }
1811}
1812
1813
1814void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001815 LOperand* left = instr->left();
1816 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001817 ASSERT(left->Equals(instr->result()));
1818 ASSERT(left->IsRegister());
1819 if (right->IsRegister()) {
1820 ASSERT(ToRegister(right).is(ecx));
1821
1822 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001823 case Token::ROR:
1824 __ ror_cl(ToRegister(left));
1825 if (instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001826 __ test(ToRegister(left), ToRegister(left));
1827 DeoptimizeIf(sign, instr->environment());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001828 }
1829 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001830 case Token::SAR:
1831 __ sar_cl(ToRegister(left));
1832 break;
1833 case Token::SHR:
1834 __ shr_cl(ToRegister(left));
1835 if (instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001836 __ test(ToRegister(left), ToRegister(left));
1837 DeoptimizeIf(sign, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001838 }
1839 break;
1840 case Token::SHL:
1841 __ shl_cl(ToRegister(left));
1842 break;
1843 default:
1844 UNREACHABLE();
1845 break;
1846 }
1847 } else {
1848 int value = ToInteger32(LConstantOperand::cast(right));
1849 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1850 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001851 case Token::ROR:
1852 if (shift_count == 0 && instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001853 __ test(ToRegister(left), ToRegister(left));
1854 DeoptimizeIf(sign, instr->environment());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001855 } else {
1856 __ ror(ToRegister(left), shift_count);
1857 }
1858 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001859 case Token::SAR:
1860 if (shift_count != 0) {
1861 __ sar(ToRegister(left), shift_count);
1862 }
1863 break;
1864 case Token::SHR:
1865 if (shift_count == 0 && instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001866 __ test(ToRegister(left), ToRegister(left));
1867 DeoptimizeIf(sign, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001868 } else {
1869 __ shr(ToRegister(left), shift_count);
1870 }
1871 break;
1872 case Token::SHL:
1873 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001874 if (instr->hydrogen_value()->representation().IsSmi() &&
1875 instr->can_deopt()) {
1876 if (shift_count != 1) {
1877 __ shl(ToRegister(left), shift_count - 1);
1878 }
1879 __ SmiTag(ToRegister(left));
1880 DeoptimizeIf(overflow, instr->environment());
1881 } else {
1882 __ shl(ToRegister(left), shift_count);
1883 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001884 }
1885 break;
1886 default:
1887 UNREACHABLE();
1888 break;
1889 }
1890 }
1891}
1892
1893
1894void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001895 LOperand* left = instr->left();
1896 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001897 ASSERT(left->Equals(instr->result()));
1898
1899 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001900 __ sub(ToOperand(left),
1901 ToImmediate(right, instr->hydrogen()->representation()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001902 } else {
1903 __ sub(ToRegister(left), ToOperand(right));
1904 }
1905 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1906 DeoptimizeIf(overflow, instr->environment());
1907 }
1908}
1909
1910
1911void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001912 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
1913}
1914
1915
1916void LCodeGen::DoConstantS(LConstantS* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001917 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001918}
1919
1920
1921void LCodeGen::DoConstantD(LConstantD* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001922 double v = instr->value();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001923 uint64_t int_val = BitCast<uint64_t, double>(v);
1924 int32_t lower = static_cast<int32_t>(int_val);
1925 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001926 ASSERT(instr->result()->IsDoubleRegister());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001927
1928 if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001929 __ push(Immediate(upper));
danno@chromium.org169691d2013-07-15 08:01:13 +00001930 __ push(Immediate(lower));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001931 X87Register reg = ToX87Register(instr->result());
1932 X87Mov(reg, Operand(esp, 0));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001933 __ add(Operand(esp), Immediate(kDoubleSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001934 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001935 CpuFeatureScope scope1(masm(), SSE2);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001936 XMMRegister res = ToDoubleRegister(instr->result());
1937 if (int_val == 0) {
1938 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001939 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001940 Register temp = ToRegister(instr->temp());
1941 if (CpuFeatures::IsSupported(SSE4_1)) {
1942 CpuFeatureScope scope2(masm(), SSE4_1);
1943 if (lower != 0) {
1944 __ Set(temp, Immediate(lower));
1945 __ movd(res, Operand(temp));
1946 __ Set(temp, Immediate(upper));
1947 __ pinsrd(res, Operand(temp), 1);
1948 } else {
1949 __ xorps(res, res);
1950 __ Set(temp, Immediate(upper));
1951 __ pinsrd(res, Operand(temp), 1);
1952 }
1953 } else {
1954 __ Set(temp, Immediate(upper));
1955 __ movd(res, Operand(temp));
1956 __ psllq(res, 32);
1957 if (lower != 0) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001958 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001959 __ Set(temp, Immediate(lower));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001960 __ movd(xmm_scratch, Operand(temp));
1961 __ por(res, xmm_scratch);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001962 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001963 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001964 }
1965 }
1966}
1967
1968
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001969void LCodeGen::DoConstantE(LConstantE* instr) {
1970 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value()));
1971}
1972
1973
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001975 Register reg = ToRegister(instr->result());
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001976 Handle<Object> handle = instr->value(isolate());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001977 AllowDeferredHandleDereference smi_check;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001978 __ LoadObject(reg, handle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001979}
1980
1981
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001982void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1983 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001984 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001985 __ EnumLength(result, map);
1986}
1987
1988
whesse@chromium.org7b260152011-06-20 15:33:18 +00001989void LCodeGen::DoElementsKind(LElementsKind* instr) {
1990 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001991 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001992
1993 // Load map into |result|.
1994 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1995 // Load the map's "bit field 2" into |result|. We only need the first byte,
1996 // but the following masking takes care of that anyway.
1997 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1998 // Retrieve elements_kind from bit field 2.
1999 __ and_(result, Map::kElementsKindMask);
2000 __ shr(result, Map::kElementsKindShift);
2001}
2002
2003
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002004void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002005 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002006 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002007 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002009
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002010 Label done;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002011
2012 if (!instr->hydrogen()->value()->IsHeapObject()) {
2013 // If the object is a smi return the object.
2014 __ JumpIfSmi(input, &done, Label::kNear);
2015 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002016
2017 // If the object is not a value type, return the object.
2018 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002019 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002020 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
2021
2022 __ bind(&done);
2023}
2024
2025
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002026void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002027 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002028 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002029 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002030 Smi* index = instr->index();
2031 Label runtime, done;
2032 ASSERT(object.is(result));
2033 ASSERT(object.is(eax));
2034
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002035 __ test(object, Immediate(kSmiTagMask));
2036 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002037 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002038 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002039
2040 if (index->value() == 0) {
2041 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
2042 } else {
2043 if (index->value() < JSDate::kFirstUncachedField) {
2044 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
2045 __ mov(scratch, Operand::StaticVariable(stamp));
2046 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
2047 __ j(not_equal, &runtime, Label::kNear);
2048 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
2049 kPointerSize * index->value()));
2050 __ jmp(&done);
2051 }
2052 __ bind(&runtime);
2053 __ PrepareCallCFunction(2, scratch);
2054 __ mov(Operand(esp, 0), object);
2055 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
2056 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
2057 __ bind(&done);
2058 }
2059}
2060
2061
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002062void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002063 Register string = ToRegister(instr->string());
2064 Register index = ToRegister(instr->index());
2065 Register value = ToRegister(instr->value());
2066 String::Encoding encoding = instr->encoding();
2067
2068 if (FLAG_debug_code) {
2069 __ push(value);
2070 __ mov(value, FieldOperand(string, HeapObject::kMapOffset));
2071 __ movzx_b(value, FieldOperand(value, Map::kInstanceTypeOffset));
2072
2073 __ and_(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
2074 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
2075 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
2076 __ cmp(value, Immediate(encoding == String::ONE_BYTE_ENCODING
2077 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00002078 __ Check(equal, kUnexpectedStringType);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002079 __ pop(value);
2080 }
2081
2082 if (encoding == String::ONE_BYTE_ENCODING) {
2083 __ mov_b(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
2084 value);
2085 } else {
2086 __ mov_w(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
2087 value);
2088 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002089}
2090
2091
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002092void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002093 __ push(ToOperand(instr->value()));
2094 ASSERT(ToRegister(instr->context()).is(esi));
2095 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002096
2097 if (FLAG_debug_code) {
2098 Comment("Unreachable code.");
2099 __ int3();
2100 }
2101}
2102
2103
2104void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002105 LOperand* left = instr->left();
2106 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002107
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002108 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
2109 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002110 int32_t offset = ToRepresentation(LConstantOperand::cast(right),
2111 instr->hydrogen()->representation());
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002112 __ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
2113 } else {
2114 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
2115 __ lea(ToRegister(instr->result()), address);
2116 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002117 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002118 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002119 __ add(ToOperand(left),
2120 ToImmediate(right, instr->hydrogen()->representation()));
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002121 } else {
2122 __ add(ToRegister(left), ToOperand(right));
2123 }
2124 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
2125 DeoptimizeIf(overflow, instr->environment());
2126 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002127 }
2128}
2129
2130
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002131void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002132 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002133 LOperand* left = instr->left();
2134 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002135 ASSERT(left->Equals(instr->result()));
2136 HMathMinMax::Operation operation = instr->hydrogen()->operation();
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002137 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002138 Label return_left;
2139 Condition condition = (operation == HMathMinMax::kMathMin)
2140 ? less_equal
2141 : greater_equal;
2142 if (right->IsConstantOperand()) {
2143 Operand left_op = ToOperand(left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002144 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->right()),
2145 instr->hydrogen()->representation());
2146 __ cmp(left_op, immediate);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002147 __ j(condition, &return_left, Label::kNear);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002148 __ mov(left_op, immediate);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002149 } else {
2150 Register left_reg = ToRegister(left);
2151 Operand right_op = ToOperand(right);
2152 __ cmp(left_reg, right_op);
2153 __ j(condition, &return_left, Label::kNear);
2154 __ mov(left_reg, right_op);
2155 }
2156 __ bind(&return_left);
2157 } else {
2158 ASSERT(instr->hydrogen()->representation().IsDouble());
2159 Label check_nan_left, check_zero, return_left, return_right;
2160 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
2161 XMMRegister left_reg = ToDoubleRegister(left);
2162 XMMRegister right_reg = ToDoubleRegister(right);
2163 __ ucomisd(left_reg, right_reg);
2164 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
2165 __ j(equal, &check_zero, Label::kNear); // left == right.
2166 __ j(condition, &return_left, Label::kNear);
2167 __ jmp(&return_right, Label::kNear);
2168
2169 __ bind(&check_zero);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002170 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002171 __ xorps(xmm_scratch, xmm_scratch);
2172 __ ucomisd(left_reg, xmm_scratch);
2173 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
2174 // At this point, both left and right are either 0 or -0.
2175 if (operation == HMathMinMax::kMathMin) {
2176 __ orpd(left_reg, right_reg);
2177 } else {
2178 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
2179 __ addsd(left_reg, right_reg);
2180 }
2181 __ jmp(&return_left, Label::kNear);
2182
2183 __ bind(&check_nan_left);
2184 __ ucomisd(left_reg, left_reg); // NaN check.
2185 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
2186 __ bind(&return_right);
2187 __ movsd(left_reg, right_reg);
2188
2189 __ bind(&return_left);
2190 }
2191}
2192
2193
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002194void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
danno@chromium.org169691d2013-07-15 08:01:13 +00002195 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2196 CpuFeatureScope scope(masm(), SSE2);
2197 XMMRegister left = ToDoubleRegister(instr->left());
2198 XMMRegister right = ToDoubleRegister(instr->right());
2199 XMMRegister result = ToDoubleRegister(instr->result());
danno@chromium.org169691d2013-07-15 08:01:13 +00002200 switch (instr->op()) {
2201 case Token::ADD:
2202 __ addsd(left, right);
2203 break;
2204 case Token::SUB:
2205 __ subsd(left, right);
2206 break;
2207 case Token::MUL:
2208 __ mulsd(left, right);
2209 break;
2210 case Token::DIV:
2211 __ divsd(left, right);
2212 // Don't delete this mov. It may improve performance on some CPUs,
2213 // when there is a mulsd depending on the result
2214 __ movaps(left, left);
2215 break;
2216 case Token::MOD: {
2217 // Pass two doubles as arguments on the stack.
2218 __ PrepareCallCFunction(4, eax);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002219 __ movsd(Operand(esp, 0 * kDoubleSize), left);
2220 __ movsd(Operand(esp, 1 * kDoubleSize), right);
danno@chromium.org169691d2013-07-15 08:01:13 +00002221 __ CallCFunction(
2222 ExternalReference::double_fp_operation(Token::MOD, isolate()),
2223 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002224
danno@chromium.org169691d2013-07-15 08:01:13 +00002225 // Return value is in st(0) on ia32.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002226 // Store it into the result register.
danno@chromium.org169691d2013-07-15 08:01:13 +00002227 __ sub(Operand(esp), Immediate(kDoubleSize));
2228 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002229 __ movsd(result, Operand(esp, 0));
danno@chromium.org169691d2013-07-15 08:01:13 +00002230 __ add(Operand(esp), Immediate(kDoubleSize));
2231 break;
2232 }
2233 default:
2234 UNREACHABLE();
2235 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002236 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002237 } else {
2238 X87Register left = ToX87Register(instr->left());
2239 X87Register right = ToX87Register(instr->right());
2240 X87Register result = ToX87Register(instr->result());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002241 if (instr->op() != Token::MOD) {
2242 X87PrepareBinaryOp(left, right, result);
2243 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002244 switch (instr->op()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002245 case Token::ADD:
2246 __ fadd_i(1);
2247 break;
2248 case Token::SUB:
2249 __ fsub_i(1);
2250 break;
danno@chromium.org169691d2013-07-15 08:01:13 +00002251 case Token::MUL:
2252 __ fmul_i(1);
2253 break;
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002254 case Token::DIV:
2255 __ fdiv_i(1);
2256 break;
2257 case Token::MOD: {
2258 // Pass two doubles as arguments on the stack.
2259 __ PrepareCallCFunction(4, eax);
2260 X87Mov(Operand(esp, 1 * kDoubleSize), right);
2261 X87Mov(Operand(esp, 0), left);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002262 X87Free(right);
2263 ASSERT(left.is(result));
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002264 X87PrepareToWrite(result);
2265 __ CallCFunction(
2266 ExternalReference::double_fp_operation(Token::MOD, isolate()),
2267 4);
2268
2269 // Return value is in st(0) on ia32.
2270 X87CommitWrite(result);
2271 break;
2272 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002273 default:
2274 UNREACHABLE();
2275 break;
2276 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002277 }
2278}
2279
2280
2281void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002282 ASSERT(ToRegister(instr->context()).is(esi));
2283 ASSERT(ToRegister(instr->left()).is(edx));
2284 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002285 ASSERT(ToRegister(instr->result()).is(eax));
2286
danno@chromium.org40cb8782011-05-25 07:58:50 +00002287 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002288 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002289 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002290}
2291
2292
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002293template<class InstrType>
2294void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002295 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002296 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002297
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002298 int next_block = GetNextEmittedBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002299
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002300 if (right_block == left_block || cc == no_condition) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002301 EmitGoto(left_block);
2302 } else if (left_block == next_block) {
2303 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2304 } else if (right_block == next_block) {
2305 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2306 } else {
2307 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2308 __ jmp(chunk_->GetAssemblyLabel(right_block));
2309 }
2310}
2311
2312
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002313template<class InstrType>
2314void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
2315 int false_block = instr->FalseDestination(chunk_);
2316 if (cc == no_condition) {
2317 __ jmp(chunk_->GetAssemblyLabel(false_block));
2318 } else {
2319 __ j(cc, chunk_->GetAssemblyLabel(false_block));
2320 }
2321}
2322
2323
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002324void LCodeGen::DoBranch(LBranch* instr) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002325 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002326 if (r.IsSmiOrInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002327 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002328 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002329 EmitBranch(instr, not_zero);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002330 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002331 ASSERT(!info()->IsStub());
2332 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002333 XMMRegister reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002334 XMMRegister xmm_scratch = double_scratch0();
2335 __ xorps(xmm_scratch, xmm_scratch);
2336 __ ucomisd(reg, xmm_scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002337 EmitBranch(instr, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002338 } else {
2339 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002340 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002341 HType type = instr->hydrogen()->value()->type();
2342 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002343 ASSERT(!info()->IsStub());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002344 __ cmp(reg, factory()->true_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002345 EmitBranch(instr, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002346 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002347 ASSERT(!info()->IsStub());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002348 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002349 EmitBranch(instr, not_equal);
2350 } else if (type.IsJSArray()) {
2351 ASSERT(!info()->IsStub());
2352 EmitBranch(instr, no_condition);
2353 } else if (type.IsHeapNumber()) {
2354 ASSERT(!info()->IsStub());
2355 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002356 XMMRegister xmm_scratch = double_scratch0();
2357 __ xorps(xmm_scratch, xmm_scratch);
2358 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002359 EmitBranch(instr, not_equal);
2360 } else if (type.IsString()) {
2361 ASSERT(!info()->IsStub());
2362 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2363 EmitBranch(instr, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 } else {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002365 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002366 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002367
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002368 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2369 // undefined -> false.
2370 __ cmp(reg, factory()->undefined_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002371 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002372 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002373 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2374 // true -> true.
2375 __ cmp(reg, factory()->true_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002376 __ j(equal, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002377 // false -> false.
2378 __ cmp(reg, factory()->false_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002379 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002380 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002381 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2382 // 'null' -> false.
2383 __ cmp(reg, factory()->null_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002384 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002385 }
2386
2387 if (expected.Contains(ToBooleanStub::SMI)) {
2388 // Smis: 0 -> false, all other -> true.
2389 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002390 __ j(equal, instr->FalseLabel(chunk_));
2391 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002392 } else if (expected.NeedsMap()) {
2393 // If we need a map later and have a Smi -> deopt.
2394 __ test(reg, Immediate(kSmiTagMask));
2395 DeoptimizeIf(zero, instr->environment());
2396 }
2397
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002398 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002399 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002400 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002401 ASSERT(!map.is(reg));
2402 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002403
2404 if (expected.CanBeUndetectable()) {
2405 // Undetectable -> false.
2406 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2407 1 << Map::kIsUndetectable);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002408 __ j(not_zero, instr->FalseLabel(chunk_));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002409 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002410 }
2411
2412 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2413 // spec object -> true.
2414 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002415 __ j(above_equal, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002416 }
2417
2418 if (expected.Contains(ToBooleanStub::STRING)) {
2419 // String value -> false iff empty.
2420 Label not_string;
2421 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2422 __ j(above_equal, &not_string, Label::kNear);
2423 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002424 __ j(not_zero, instr->TrueLabel(chunk_));
2425 __ jmp(instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002426 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002427 }
2428
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002429 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2430 // Symbol value -> true.
2431 __ CmpInstanceType(map, SYMBOL_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002432 __ j(equal, instr->TrueLabel(chunk_));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002433 }
2434
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002435 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2436 // heap number -> false iff +0, -0, or NaN.
2437 Label not_heap_number;
2438 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2439 factory()->heap_number_map());
2440 __ j(not_equal, &not_heap_number, Label::kNear);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002441 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2442 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002443 XMMRegister xmm_scratch = double_scratch0();
2444 __ xorps(xmm_scratch, xmm_scratch);
2445 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002446 } else {
2447 __ fldz();
2448 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
2449 __ FCmp();
2450 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002451 __ j(zero, instr->FalseLabel(chunk_));
2452 __ jmp(instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002453 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002454 }
2455
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002456 if (!expected.IsGeneric()) {
2457 // We've seen something for the first time -> deopt.
2458 // This can only happen if we are not generic already.
2459 DeoptimizeIf(no_condition, instr->environment());
2460 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002461 }
2462 }
2463}
2464
2465
ager@chromium.org04921a82011-06-27 13:21:41 +00002466void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002467 if (!IsNextEmittedBlock(block)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002468 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002469 }
2470}
2471
2472
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002473void LCodeGen::DoClobberDoubles(LClobberDoubles* instr) {
2474}
2475
2476
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002477void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479}
2480
2481
2482Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2483 Condition cond = no_condition;
2484 switch (op) {
2485 case Token::EQ:
2486 case Token::EQ_STRICT:
2487 cond = equal;
2488 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002489 case Token::NE:
2490 case Token::NE_STRICT:
2491 cond = not_equal;
2492 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002493 case Token::LT:
2494 cond = is_unsigned ? below : less;
2495 break;
2496 case Token::GT:
2497 cond = is_unsigned ? above : greater;
2498 break;
2499 case Token::LTE:
2500 cond = is_unsigned ? below_equal : less_equal;
2501 break;
2502 case Token::GTE:
2503 cond = is_unsigned ? above_equal : greater_equal;
2504 break;
2505 case Token::IN:
2506 case Token::INSTANCEOF:
2507 default:
2508 UNREACHABLE();
2509 }
2510 return cond;
2511}
2512
2513
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002514void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002515 LOperand* left = instr->left();
2516 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002517 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002518
2519 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2520 // We can statically evaluate the comparison.
2521 double left_val = ToDouble(LConstantOperand::cast(left));
2522 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002523 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2524 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002525 EmitGoto(next_block);
2526 } else {
2527 if (instr->is_double()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002528 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2529 CpuFeatureScope scope(masm(), SSE2);
2530 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2531 } else {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002532 X87LoadForUsage(ToX87Register(right), ToX87Register(left));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002533 __ FCmp();
2534 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002535 // Don't base result on EFLAGS when a NaN is involved. Instead
2536 // jump to the false block.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002537 __ j(parity_even, instr->FalseLabel(chunk_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002538 } else {
2539 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002540 __ cmp(ToOperand(left),
2541 ToImmediate(right, instr->hydrogen()->representation()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002542 } else if (left->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002543 __ cmp(ToOperand(right),
2544 ToImmediate(left, instr->hydrogen()->representation()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002545 // We transposed the operands. Reverse the condition.
2546 cc = ReverseCondition(cc);
2547 } else {
2548 __ cmp(ToRegister(left), ToOperand(right));
2549 }
2550 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002551 EmitBranch(instr, cc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002552 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002553}
2554
2555
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002556void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002557 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002558
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002559 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002560 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
2561 __ CmpObject(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002562 } else {
2563 Operand right = ToOperand(instr->right());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002564 __ cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002565 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002566 EmitBranch(instr, equal);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002567}
2568
2569
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002570void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2571 if (instr->hydrogen()->representation().IsTagged()) {
2572 Register input_reg = ToRegister(instr->object());
2573 __ cmp(input_reg, factory()->the_hole_value());
2574 EmitBranch(instr, equal);
2575 return;
2576 }
2577
2578 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
2579 if (use_sse2) {
2580 CpuFeatureScope scope(masm(), SSE2);
2581 XMMRegister input_reg = ToDoubleRegister(instr->object());
2582 __ ucomisd(input_reg, input_reg);
2583 EmitFalseBranch(instr, parity_odd);
2584 } else {
2585 // Put the value to the top of stack
2586 X87Register src = ToX87Register(instr->object());
2587 X87LoadForUsage(src);
2588 __ fld(0);
2589 __ fld(0);
2590 __ FCmp();
2591 Label ok;
2592 __ j(parity_even, &ok);
2593 __ fstp(0);
2594 EmitFalseBranch(instr, no_condition);
2595 __ bind(&ok);
2596 }
2597
2598
2599 __ sub(esp, Immediate(kDoubleSize));
2600 if (use_sse2) {
2601 CpuFeatureScope scope(masm(), SSE2);
2602 XMMRegister input_reg = ToDoubleRegister(instr->object());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002603 __ movsd(MemOperand(esp, 0), input_reg);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002604 } else {
2605 __ fstp_d(MemOperand(esp, 0));
2606 }
2607
2608 __ add(esp, Immediate(kDoubleSize));
2609 int offset = sizeof(kHoleNanUpper32);
2610 __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32));
2611 EmitBranch(instr, equal);
2612}
2613
2614
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002615Condition LCodeGen::EmitIsObject(Register input,
2616 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002617 Label* is_not_object,
2618 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002619 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002620
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002621 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002622 __ j(equal, is_object);
2623
2624 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2625 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002626 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2627 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002628 __ j(not_zero, is_not_object);
2629
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002630 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2631 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002632 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002633 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002634 return below_equal;
2635}
2636
2637
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002638void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002639 Register reg = ToRegister(instr->value());
2640 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002641
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002642 Condition true_cond = EmitIsObject(
2643 reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002644
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002645 EmitBranch(instr, true_cond);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002646}
2647
2648
erikcorry0ad885c2011-11-21 13:51:57 +00002649Condition LCodeGen::EmitIsString(Register input,
2650 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002651 Label* is_not_string,
2652 SmiCheck check_needed = INLINE_SMI_CHECK) {
2653 if (check_needed == INLINE_SMI_CHECK) {
2654 __ JumpIfSmi(input, is_not_string);
2655 }
erikcorry0ad885c2011-11-21 13:51:57 +00002656
2657 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2658
2659 return cond;
2660}
2661
2662
2663void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002664 Register reg = ToRegister(instr->value());
2665 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002666
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002667 SmiCheck check_needed =
2668 instr->hydrogen()->value()->IsHeapObject()
2669 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erikcorry0ad885c2011-11-21 13:51:57 +00002670
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002671 Condition true_cond = EmitIsString(
2672 reg, temp, instr->FalseLabel(chunk_), check_needed);
erikcorry0ad885c2011-11-21 13:51:57 +00002673
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002674 EmitBranch(instr, true_cond);
erikcorry0ad885c2011-11-21 13:51:57 +00002675}
2676
2677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002678void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002679 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002680
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002681 __ test(input, Immediate(kSmiTagMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002682 EmitBranch(instr, zero);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002683}
2684
2685
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002686void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002687 Register input = ToRegister(instr->value());
2688 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002689
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002690 if (!instr->hydrogen()->value()->IsHeapObject()) {
2691 STATIC_ASSERT(kSmiTag == 0);
2692 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2693 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002694 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2695 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2696 1 << Map::kIsUndetectable);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002697 EmitBranch(instr, not_zero);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002698}
2699
2700
erikcorry0ad885c2011-11-21 13:51:57 +00002701static Condition ComputeCompareCondition(Token::Value op) {
2702 switch (op) {
2703 case Token::EQ_STRICT:
2704 case Token::EQ:
2705 return equal;
2706 case Token::LT:
2707 return less;
2708 case Token::GT:
2709 return greater;
2710 case Token::LTE:
2711 return less_equal;
2712 case Token::GTE:
2713 return greater_equal;
2714 default:
2715 UNREACHABLE();
2716 return no_condition;
2717 }
2718}
2719
2720
2721void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2722 Token::Value op = instr->op();
erikcorry0ad885c2011-11-21 13:51:57 +00002723
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002724 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002725 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2726
2727 Condition condition = ComputeCompareCondition(op);
2728 __ test(eax, Operand(eax));
2729
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002730 EmitBranch(instr, condition);
erikcorry0ad885c2011-11-21 13:51:57 +00002731}
2732
2733
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002734static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002735 InstanceType from = instr->from();
2736 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002737 if (from == FIRST_TYPE) return to;
2738 ASSERT(from == to || to == LAST_TYPE);
2739 return from;
2740}
2741
2742
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002743static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002744 InstanceType from = instr->from();
2745 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002746 if (from == to) return equal;
2747 if (to == LAST_TYPE) return above_equal;
2748 if (from == FIRST_TYPE) return below_equal;
2749 UNREACHABLE();
2750 return equal;
2751}
2752
2753
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002754void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002755 Register input = ToRegister(instr->value());
2756 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002757
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002758 if (!instr->hydrogen()->value()->IsHeapObject()) {
2759 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2760 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002761
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002762 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002763 EmitBranch(instr, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002764}
2765
2766
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002767void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002768 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002769 Register result = ToRegister(instr->result());
2770
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002771 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002772
2773 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2774 __ IndexFromHash(result, result);
2775}
2776
2777
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002778void LCodeGen::DoHasCachedArrayIndexAndBranch(
2779 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002780 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002781
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002782 __ test(FieldOperand(input, String::kHashFieldOffset),
2783 Immediate(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002784 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002785}
2786
2787
2788// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002789// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002790void LCodeGen::EmitClassOfTest(Label* is_true,
2791 Label* is_false,
2792 Handle<String>class_name,
2793 Register input,
2794 Register temp,
2795 Register temp2) {
2796 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002797 ASSERT(!input.is(temp2));
2798 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002799 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002800
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002801 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002802 // Assuming the following assertions, we can use the same compares to test
2803 // for both being a function type and being in the object type range.
2804 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2805 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2806 FIRST_SPEC_OBJECT_TYPE + 1);
2807 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2808 LAST_SPEC_OBJECT_TYPE - 1);
2809 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2810 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2811 __ j(below, is_false);
2812 __ j(equal, is_true);
2813 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2814 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002815 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002816 // Faster code path to avoid two compares: subtract lower bound from the
2817 // actual type and do a signed compare with the width of the type range.
2818 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002819 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002820 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002821 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2822 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002823 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002824 }
2825
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002826 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002827 // Check if the constructor in the map is a function.
2828 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002829 // Objects with a non-function constructor have class 'Object'.
2830 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002831 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002832 __ j(not_equal, is_true);
2833 } else {
2834 __ j(not_equal, is_false);
2835 }
2836
2837 // temp now contains the constructor function. Grab the
2838 // instance class name from there.
2839 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2840 __ mov(temp, FieldOperand(temp,
2841 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002842 // The class name we are testing against is internalized since it's a literal.
2843 // The name in the constructor is internalized because of the way the context
2844 // is booted. This routine isn't expected to work for random API-created
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002845 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002846 // syntax. Since both sides are internalized it is sufficient to use an
2847 // identity comparison.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002848 __ cmp(temp, class_name);
2849 // End with the answer in the z flag.
2850}
2851
2852
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002853void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002854 Register input = ToRegister(instr->value());
2855 Register temp = ToRegister(instr->temp());
2856 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002857
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002858 Handle<String> class_name = instr->hydrogen()->class_name();
2859
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002860 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2861 class_name, input, temp, temp2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002862
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002863 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002864}
2865
2866
2867void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002868 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002869 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002870 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002871}
2872
2873
2874void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002875 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002876 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002877 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002878 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002879
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002880 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002881 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002882 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002883 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002884 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002885 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002886 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002887 __ bind(&done);
2888}
2889
2890
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002891void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002892 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002893 public:
2894 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00002895 LInstanceOfKnownGlobal* instr,
2896 const X87Stack& x87_stack)
2897 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002898 virtual void Generate() V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002899 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002900 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002901 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002902 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002903 private:
2904 LInstanceOfKnownGlobal* instr_;
2905 Label map_check_;
2906 };
2907
2908 DeferredInstanceOfKnownGlobal* deferred;
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00002909 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr, x87_stack_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002910
2911 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002912 Register object = ToRegister(instr->value());
2913 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002914
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002915 // A Smi is not an instance of anything.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002916 __ JumpIfSmi(object, &false_result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002917
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002918 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002919 // hole value will be patched to the last map/result pair generated by the
2920 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002921 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002922 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002923 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2924 __ bind(deferred->map_check()); // Label for calculating code patching.
danno@chromium.org41728482013-06-12 22:31:22 +00002925 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2926 __ cmp(map, Operand::ForCell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002927 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002929 __ jmp(&done);
2930
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002931 // The inlined call site cache did not match. Check for null and string
2932 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002933 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002934 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002935 __ cmp(object, factory()->null_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002936 __ j(equal, &false_result);
2937
2938 // String values are not instances of anything.
2939 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
2940 __ j(is_string, &false_result);
2941
2942 // Go to the deferred code.
2943 __ jmp(deferred->entry());
2944
2945 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002946 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002947
2948 // Here result has either true or false. Deferred code also produces true or
2949 // false object.
2950 __ bind(deferred->exit());
2951 __ bind(&done);
2952}
2953
2954
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002955void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2956 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002957 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002958
2959 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2960 flags = static_cast<InstanceofStub::Flags>(
2961 flags | InstanceofStub::kArgsInRegisters);
2962 flags = static_cast<InstanceofStub::Flags>(
2963 flags | InstanceofStub::kCallSiteInlineCheck);
2964 flags = static_cast<InstanceofStub::Flags>(
2965 flags | InstanceofStub::kReturnTrueFalseObject);
2966 InstanceofStub stub(flags);
2967
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002968 // Get the temp register reserved by the instruction. This needs to be a
2969 // register which is pushed last by PushSafepointRegisters as top of the
2970 // stack is used to pass the offset to the location of the map check to
2971 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002972 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002973 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002974 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002975 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002976 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002977 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002978 __ StoreToSafepointRegisterSlot(temp, temp);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002979 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002980 RelocInfo::CODE_TARGET,
2981 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002982 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002983 // Get the deoptimization index of the LLazyBailout-environment that
2984 // corresponds to this instruction.
2985 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002986 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2987
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002988 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002989 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002990}
2991
2992
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002993void LCodeGen::DoCmpT(LCmpT* instr) {
2994 Token::Value op = instr->op();
2995
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002996 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002997 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002998
2999 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003000 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003001 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003002 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003003 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003004 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003005 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003006 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003007 __ bind(&done);
3008}
3009
3010
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003011void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) {
3012 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
3013
3014 if (instr->has_constant_parameter_count()) {
3015 int parameter_count = ToInteger32(instr->constant_parameter_count());
3016 if (dynamic_frame_alignment && FLAG_debug_code) {
3017 __ cmp(Operand(esp,
3018 (parameter_count + extra_value_count) * kPointerSize),
3019 Immediate(kAlignmentZapValue));
danno@chromium.org59400602013-08-13 17:09:37 +00003020 __ Assert(equal, kExpectedAlignmentMarker);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003021 }
3022 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
3023 } else {
3024 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003025 // The argument count parameter is a smi
3026 __ SmiUntag(reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003027 Register return_addr_reg = reg.is(ecx) ? ebx : ecx;
3028 if (dynamic_frame_alignment && FLAG_debug_code) {
3029 ASSERT(extra_value_count == 2);
3030 __ cmp(Operand(esp, reg, times_pointer_size,
3031 extra_value_count * kPointerSize),
3032 Immediate(kAlignmentZapValue));
danno@chromium.org59400602013-08-13 17:09:37 +00003033 __ Assert(equal, kExpectedAlignmentMarker);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003034 }
3035
3036 // emit code to restore stack based on instr->parameter_count()
3037 __ pop(return_addr_reg); // save return address
3038 if (dynamic_frame_alignment) {
3039 __ inc(reg); // 1 more for alignment
3040 }
3041 __ shl(reg, kPointerSizeLog2);
3042 __ add(esp, reg);
3043 __ jmp(return_addr_reg);
3044 }
3045}
3046
3047
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003048void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003049 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003050 // Preserve the return value on the stack and rely on the runtime call
3051 // to return the value in the same register. We're leaving the code
3052 // managed by the register allocator and tearing down the frame, it's
3053 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003054 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003055 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003056 __ CallRuntime(Runtime::kTraceExit, 1);
3057 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003058 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
3059 ASSERT(NeedsEagerFrame());
ulan@chromium.org750145a2013-03-07 15:14:13 +00003060 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003061 BitVector* doubles = chunk()->allocated_double_registers();
3062 BitVector::Iterator save_iterator(doubles);
3063 int count = 0;
3064 while (!save_iterator.Done()) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003065 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003066 MemOperand(esp, count * kDoubleSize));
3067 save_iterator.Advance();
3068 count++;
3069 }
3070 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003071 if (dynamic_frame_alignment_) {
3072 // Fetch the state of the dynamic frame alignment.
3073 __ mov(edx, Operand(ebp,
3074 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
3075 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003076 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003077 if (NeedsEagerFrame()) {
3078 __ mov(esp, ebp);
3079 __ pop(ebp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003080 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003081 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003082 if (dynamic_frame_alignment_) {
3083 Label no_padding;
3084 __ cmp(edx, Immediate(kNoAlignmentPadding));
3085 __ j(equal, &no_padding);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003086
3087 EmitReturn(instr, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003088 __ bind(&no_padding);
3089 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003090
3091 EmitReturn(instr, false);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003092 if (no_frame_start != -1) {
3093 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
3094 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003095}
3096
3097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003098void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003099 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003100 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003101 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003102 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003103 DeoptimizeIf(equal, instr->environment());
3104 }
3105}
3106
3107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003108void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
3109 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003110 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003111 ASSERT(ToRegister(instr->result()).is(eax));
3112
3113 __ mov(ecx, instr->name());
3114 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
3115 RelocInfo::CODE_TARGET_CONTEXT;
3116 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003117 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003118}
3119
3120
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003121void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00003122 Register value = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003123 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003124
3125 // If the cell we are storing to contains the hole it could have
3126 // been deleted from the property dictionary. In that case, we need
3127 // to update the property details in the property dictionary to mark
3128 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003129 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.org41728482013-06-12 22:31:22 +00003130 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003131 DeoptimizeIf(equal, instr->environment());
3132 }
3133
3134 // Store the value.
danno@chromium.org41728482013-06-12 22:31:22 +00003135 __ mov(Operand::ForCell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003136 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003137}
3138
3139
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003140void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
3141 ASSERT(ToRegister(instr->context()).is(esi));
3142 ASSERT(ToRegister(instr->global_object()).is(edx));
3143 ASSERT(ToRegister(instr->value()).is(eax));
3144
3145 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003146 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003147 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3148 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003149 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003150}
3151
3152
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003153void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003154 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003155 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003156 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003157
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003158 if (instr->hydrogen()->RequiresHoleCheck()) {
3159 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003160 if (instr->hydrogen()->DeoptimizesOnHole()) {
3161 DeoptimizeIf(equal, instr->environment());
3162 } else {
3163 Label is_not_hole;
3164 __ j(not_equal, &is_not_hole, Label::kNear);
3165 __ mov(result, factory()->undefined_value());
3166 __ bind(&is_not_hole);
3167 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003168 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003169}
3170
3171
3172void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
3173 Register context = ToRegister(instr->context());
3174 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003175
3176 Label skip_assignment;
3177
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003178 Operand target = ContextOperand(context, instr->slot_index());
3179 if (instr->hydrogen()->RequiresHoleCheck()) {
3180 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003181 if (instr->hydrogen()->DeoptimizesOnHole()) {
3182 DeoptimizeIf(equal, instr->environment());
3183 } else {
3184 __ j(not_equal, &skip_assignment, Label::kNear);
3185 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003186 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003187
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003188 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003189 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003190 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003191 instr->hydrogen()->value()->IsHeapObject()
3192 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003193 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003194 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003195 __ RecordWriteContextSlot(context,
3196 offset,
3197 value,
3198 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003199 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003200 EMIT_REMEMBERED_SET,
3201 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003202 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003203
3204 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003205}
3206
3207
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003208void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003209 HObjectAccess access = instr->hydrogen()->access();
3210 int offset = access.offset();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003211
3212 if (access.IsExternalMemory()) {
3213 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003214 MemOperand operand = instr->object()->IsConstantOperand()
3215 ? MemOperand::StaticVariable(ToExternalReference(
3216 LConstantOperand::cast(instr->object())))
3217 : MemOperand(ToRegister(instr->object()), offset);
3218 if (access.representation().IsByte()) {
3219 ASSERT(instr->hydrogen()->representation().IsInteger32());
3220 __ movzx_b(result, operand);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003221 } else {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003222 __ mov(result, operand);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003223 }
3224 return;
3225 }
3226
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003227 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003228 if (FLAG_track_double_fields &&
3229 instr->hydrogen()->representation().IsDouble()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003230 if (CpuFeatures::IsSupported(SSE2)) {
3231 CpuFeatureScope scope(masm(), SSE2);
3232 XMMRegister result = ToDoubleRegister(instr->result());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003233 __ movsd(result, FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00003234 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003235 X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00003236 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003237 return;
3238 }
3239
3240 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003241 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003242 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003243 object = result;
3244 }
3245 if (access.representation().IsByte()) {
3246 ASSERT(instr->hydrogen()->representation().IsInteger32());
3247 __ movzx_b(result, FieldOperand(object, offset));
3248 } else {
3249 __ mov(result, FieldOperand(object, offset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003250 }
3251}
3252
3253
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003254void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
3255 ASSERT(!operand->IsDoubleRegister());
3256 if (operand->IsConstantOperand()) {
3257 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003258 AllowDeferredHandleDereference smi_check;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003259 if (object->IsSmi()) {
3260 __ Push(Handle<Smi>::cast(object));
3261 } else {
3262 __ PushHeapObject(Handle<HeapObject>::cast(object));
3263 }
3264 } else if (operand->IsRegister()) {
3265 __ push(ToRegister(operand));
3266 } else {
3267 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003268 }
3269}
3270
3271
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003272void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003273 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003274 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003275 ASSERT(ToRegister(instr->result()).is(eax));
3276
3277 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003278 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003279 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003280}
3281
3282
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003283void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3284 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003285 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003286 Register result = ToRegister(instr->result());
3287
3288 // Check that the function really is a function.
3289 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
3290 DeoptimizeIf(not_equal, instr->environment());
3291
3292 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003293 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003294 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
3295 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003296 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003297
3298 // Get the prototype or initial map from the function.
3299 __ mov(result,
3300 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3301
3302 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003303 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003304 DeoptimizeIf(equal, instr->environment());
3305
3306 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003307 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003308 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003309 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003310
3311 // Get the prototype from the initial map.
3312 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003313 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003314
3315 // Non-instance prototype: Fetch prototype from constructor field
3316 // in the function's map.
3317 __ bind(&non_instance);
3318 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
3319
3320 // All done.
3321 __ bind(&done);
3322}
3323
3324
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003325void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3326 Register result = ToRegister(instr->result());
3327 __ LoadRoot(result, instr->index());
3328}
3329
3330
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003331void LCodeGen::DoLoadExternalArrayPointer(
3332 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003333 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003334 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003335 __ mov(result, FieldOperand(input,
3336 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003337}
3338
3339
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003340void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3341 Register arguments = ToRegister(instr->arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003342 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003343 if (instr->length()->IsConstantOperand() &&
3344 instr->index()->IsConstantOperand()) {
3345 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3346 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3347 int index = (const_length - const_index) + 1;
3348 __ mov(result, Operand(arguments, index * kPointerSize));
3349 } else {
3350 Register length = ToRegister(instr->length());
3351 Operand index = ToOperand(instr->index());
3352 // There are two words between the frame pointer and the last argument.
3353 // Subtracting from length accounts for one of them add one more.
3354 __ sub(length, index);
3355 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3356 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003357}
3358
3359
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003360void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003361 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003362 LOperand* key = instr->key();
3363 if (!key->IsConstantOperand() &&
3364 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3365 elements_kind)) {
3366 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003367 }
3368 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003369 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003370 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003371 instr->hydrogen()->key()->representation(),
3372 elements_kind,
3373 0,
3374 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003375 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003376 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003377 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003378 XMMRegister result(ToDoubleRegister(instr->result()));
3379 __ movss(result, operand);
3380 __ cvtss2sd(result, result);
3381 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003382 X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003383 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003384 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003385 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003386 CpuFeatureScope scope(masm(), SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003387 __ movsd(ToDoubleRegister(instr->result()), operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003388 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003389 X87Mov(ToX87Register(instr->result()), operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003390 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003391 } else {
3392 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003393 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003394 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003395 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003396 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003397 case EXTERNAL_PIXEL_ELEMENTS:
3398 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003399 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003400 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003401 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003402 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003403 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003404 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003405 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003406 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003407 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003408 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003409 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003410 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003411 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003412 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3413 __ test(result, Operand(result));
3414 DeoptimizeIf(negative, instr->environment());
3415 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003416 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003417 case EXTERNAL_FLOAT_ELEMENTS:
3418 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003419 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003420 case FAST_ELEMENTS:
3421 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003422 case FAST_HOLEY_SMI_ELEMENTS:
3423 case FAST_HOLEY_ELEMENTS:
3424 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003425 case DICTIONARY_ELEMENTS:
3426 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003427 UNREACHABLE();
3428 break;
3429 }
3430 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003431}
3432
3433
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003434void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003435 if (instr->hydrogen()->RequiresHoleCheck()) {
3436 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3437 sizeof(kHoleNanLower32);
3438 Operand hole_check_operand = BuildFastArrayOperand(
3439 instr->elements(), instr->key(),
3440 instr->hydrogen()->key()->representation(),
3441 FAST_DOUBLE_ELEMENTS,
3442 offset,
3443 instr->additional_index());
3444 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3445 DeoptimizeIf(equal, instr->environment());
3446 }
3447
3448 Operand double_load_operand = BuildFastArrayOperand(
3449 instr->elements(),
3450 instr->key(),
3451 instr->hydrogen()->key()->representation(),
3452 FAST_DOUBLE_ELEMENTS,
3453 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3454 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003455 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003456 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003457 XMMRegister result = ToDoubleRegister(instr->result());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003458 __ movsd(result, double_load_operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003459 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003460 X87Mov(ToX87Register(instr->result()), double_load_operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003461 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003462}
3463
3464
3465void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3466 Register result = ToRegister(instr->result());
3467
3468 // Load the result.
3469 __ mov(result,
3470 BuildFastArrayOperand(instr->elements(),
3471 instr->key(),
3472 instr->hydrogen()->key()->representation(),
3473 FAST_ELEMENTS,
3474 FixedArray::kHeaderSize - kHeapObjectTag,
3475 instr->additional_index()));
3476
3477 // Check for the hole value.
3478 if (instr->hydrogen()->RequiresHoleCheck()) {
3479 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3480 __ test(result, Immediate(kSmiTagMask));
3481 DeoptimizeIf(not_equal, instr->environment());
3482 } else {
3483 __ cmp(result, factory()->the_hole_value());
3484 DeoptimizeIf(equal, instr->environment());
3485 }
3486 }
3487}
3488
3489
3490void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3491 if (instr->is_external()) {
3492 DoLoadKeyedExternalArray(instr);
3493 } else if (instr->hydrogen()->representation().IsDouble()) {
3494 DoLoadKeyedFixedDoubleArray(instr);
3495 } else {
3496 DoLoadKeyedFixedArray(instr);
3497 }
3498}
3499
3500
3501Operand LCodeGen::BuildFastArrayOperand(
3502 LOperand* elements_pointer,
3503 LOperand* key,
3504 Representation key_representation,
3505 ElementsKind elements_kind,
3506 uint32_t offset,
3507 uint32_t additional_index) {
3508 Register elements_pointer_reg = ToRegister(elements_pointer);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003509 int element_shift_size = ElementsKindToShiftSize(elements_kind);
3510 int shift_size = element_shift_size;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003511 if (key->IsConstantOperand()) {
3512 int constant_value = ToInteger32(LConstantOperand::cast(key));
3513 if (constant_value & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003514 Abort(kArrayIndexConstantValueTooBig);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003515 }
3516 return Operand(elements_pointer_reg,
3517 ((constant_value + additional_index) << shift_size)
3518 + offset);
3519 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003520 // Take the tag bit into account while computing the shift size.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003521 if (key_representation.IsSmi() && (shift_size >= 1)) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003522 shift_size -= kSmiTagSize;
3523 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003524 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3525 return Operand(elements_pointer_reg,
3526 ToRegister(key),
3527 scale_factor,
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003528 offset + (additional_index << element_shift_size));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003529 }
3530}
3531
3532
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003533void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003534 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003535 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003536 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003537
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003538 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003539 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003540}
3541
3542
3543void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3544 Register result = ToRegister(instr->result());
3545
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003546 if (instr->hydrogen()->from_inlined()) {
3547 __ lea(result, Operand(esp, -2 * kPointerSize));
3548 } else {
3549 // Check for arguments adapter frame.
3550 Label done, adapted;
3551 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3552 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3553 __ cmp(Operand(result),
3554 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3555 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003556
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003557 // No arguments adaptor frame.
3558 __ mov(result, Operand(ebp));
3559 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003560
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003561 // Arguments adaptor frame present.
3562 __ bind(&adapted);
3563 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003564
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003565 // Result is the frame pointer for the frame if not adapted and for the real
3566 // frame below the adaptor frame if adapted.
3567 __ bind(&done);
3568 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003569}
3570
3571
3572void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003573 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003574 Register result = ToRegister(instr->result());
3575
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003576 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003577
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003578 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003579 __ cmp(ebp, elem);
3580 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003581 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003582
3583 // Arguments adaptor frame present. Get argument length from there.
3584 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3585 __ mov(result, Operand(result,
3586 ArgumentsAdaptorFrameConstants::kLengthOffset));
3587 __ SmiUntag(result);
3588
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003589 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003590 __ bind(&done);
3591}
3592
3593
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003594void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003595 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003596 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003597 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003598
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003599 // If the receiver is null or undefined, we have to pass the global
3600 // object as a receiver to normal functions. Values have to be
3601 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003602 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003603
3604 // Do not transform the receiver to object for strict mode
3605 // functions.
3606 __ mov(scratch,
3607 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3608 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3609 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003610 __ j(not_equal, &receiver_ok); // A near jump is not sufficient here!
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003611
3612 // Do not transform the receiver to object for builtins.
3613 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3614 1 << SharedFunctionInfo::kNativeBitWithinByte);
danno@chromium.org412fa512012-09-14 13:28:26 +00003615 __ j(not_equal, &receiver_ok);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003616
3617 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003619 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003621 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003622
3623 // The receiver should be a JS object.
3624 __ test(receiver, Immediate(kSmiTagMask));
3625 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003626 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003627 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003628 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003629
3630 __ bind(&global_object);
3631 // TODO(kmillikin): We have a hydrogen value for the global object. See
3632 // if it's better to use it than to explicitly fetch it from the context
3633 // here.
3634 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003635 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003636 __ mov(receiver,
3637 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003638 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003639}
3640
3641
3642void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3643 Register receiver = ToRegister(instr->receiver());
3644 Register function = ToRegister(instr->function());
3645 Register length = ToRegister(instr->length());
3646 Register elements = ToRegister(instr->elements());
3647 ASSERT(receiver.is(eax)); // Used for parameter count.
3648 ASSERT(function.is(edi)); // Required by InvokeFunction.
3649 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003650
3651 // Copy the arguments to this function possibly from the
3652 // adaptor frame below it.
3653 const uint32_t kArgumentsLimit = 1 * KB;
3654 __ cmp(length, kArgumentsLimit);
3655 DeoptimizeIf(above, instr->environment());
3656
3657 __ push(receiver);
3658 __ mov(receiver, length);
3659
3660 // Loop through the arguments pushing them onto the execution
3661 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003662 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003663 // length is a small non-negative integer, due to the test above.
3664 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003665 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003666 __ bind(&loop);
3667 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3668 __ dec(length);
3669 __ j(not_zero, &loop);
3670
3671 // Invoke the function.
3672 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003673 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003674 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003675 SafepointGenerator safepoint_generator(
3676 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003677 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003678 __ InvokeFunction(function, actual, CALL_FUNCTION,
3679 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003680}
3681
3682
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003683void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
3684 __ int3();
3685}
3686
3687
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003688void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003689 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003690 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003691}
3692
3693
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003694void LCodeGen::DoDrop(LDrop* instr) {
3695 __ Drop(instr->count());
3696}
3697
3698
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003699void LCodeGen::DoThisFunction(LThisFunction* instr) {
3700 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003701 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003702}
3703
3704
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003705void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003706 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003707 if (info()->IsOptimizing()) {
3708 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3709 } else {
3710 // If there is no frame, the context must be in esi.
3711 ASSERT(result.is(esi));
3712 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003713}
3714
3715
3716void LCodeGen::DoOuterContext(LOuterContext* instr) {
3717 Register context = ToRegister(instr->context());
3718 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003719 __ mov(result,
3720 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003721}
3722
3723
yangguo@chromium.org56454712012-02-16 15:33:53 +00003724void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003725 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003726 __ push(esi); // The context is the first argument.
3727 __ push(Immediate(instr->hydrogen()->pairs()));
3728 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3729 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3730}
3731
3732
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003733void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3734 Register context = ToRegister(instr->context());
3735 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003736 __ mov(result,
3737 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003738}
3739
3740
3741void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003742 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003743 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003744 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003745}
3746
3747
3748void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003749 int formal_parameter_count,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003750 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003751 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003752 CallKind call_kind,
3753 EDIState edi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003754 bool dont_adapt_arguments =
3755 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3756 bool can_invoke_directly =
3757 dont_adapt_arguments || formal_parameter_count == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003758
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003759 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003760 if (edi_state == EDI_UNINITIALIZED) {
3761 __ LoadHeapObject(edi, function);
3762 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003763
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003764 // Change context.
3765 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003766
3767 // Set eax to arguments count if adaption is not needed. Assumes that eax
3768 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003769 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003770 __ mov(eax, arity);
3771 }
3772
3773 // Invoke function directly.
3774 __ SetCallKind(ecx, call_kind);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003775 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003776 __ CallSelf();
3777 } else {
3778 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3779 }
3780 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3781 } else {
3782 // We need to adapt arguments.
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00003783 LPointerMap* pointers = instr->pointer_map();
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003784 SafepointGenerator generator(
3785 this, pointers, Safepoint::kLazyDeopt);
3786 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003787 ParameterCount expected(formal_parameter_count);
3788 __ InvokeFunction(
3789 function, expected, count, CALL_FUNCTION, generator, call_kind);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003790 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003791}
3792
3793
3794void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3795 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003796 CallKnownFunction(instr->hydrogen()->function(),
3797 instr->hydrogen()->formal_parameter_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00003798 instr->arity(),
3799 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003800 CALL_AS_METHOD,
3801 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003802}
3803
3804
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003805void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003806 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003807 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003808 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003809 DeoptimizeIf(not_equal, instr->environment());
3810
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003811 Label slow, allocated, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003812 Register tmp = input_reg.is(eax) ? ecx : eax;
3813 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3814
3815 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003816 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003817
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003818 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003819 // Check the sign of the argument. If the argument is positive, just
3820 // return it. We do not need to patch the stack since |input| and
3821 // |result| are the same register and |input| will be restored
3822 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003823 __ test(tmp, Immediate(HeapNumber::kSignMask));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003824 __ j(zero, &done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003825
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003826 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003827 __ jmp(&allocated, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003828
3829 // Slow case: Call the runtime system to do the number allocation.
3830 __ bind(&slow);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003831 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3832 instr, instr->context());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003833 // Set the pointer to the new heap number in tmp.
3834 if (!tmp.is(eax)) __ mov(tmp, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003835 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003836 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003837
3838 __ bind(&allocated);
3839 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3840 __ and_(tmp2, ~HeapNumber::kSignMask);
3841 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3842 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3843 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003844 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003845
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003846 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003847}
3848
3849
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003850void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003851 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003852 __ test(input_reg, Operand(input_reg));
3853 Label is_positive;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003854 __ j(not_sign, &is_positive, Label::kNear);
3855 __ neg(input_reg); // Sets flags.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003856 DeoptimizeIf(negative, instr->environment());
3857 __ bind(&is_positive);
3858}
3859
3860
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003861void LCodeGen::DoMathAbs(LMathAbs* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003862 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003863 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003864 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003865 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3866 LMathAbs* instr,
3867 const X87Stack& x87_stack)
3868 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003869 virtual void Generate() V8_OVERRIDE {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3871 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003872 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003873 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003874 LMathAbs* instr_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003875 };
3876
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003877 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003878 Representation r = instr->hydrogen()->value()->representation();
3879
ulan@chromium.org750145a2013-03-07 15:14:13 +00003880 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003881 if (r.IsDouble()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003882 XMMRegister scratch = double_scratch0();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003883 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003884 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003885 __ subsd(scratch, input_reg);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00003886 __ andps(input_reg, scratch);
danno@chromium.org59400602013-08-13 17:09:37 +00003887 } else if (r.IsSmiOrInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003888 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003889 } else { // Tagged case.
3890 DeferredMathAbsTaggedHeapNumber* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003891 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr, x87_stack_);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003892 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003893 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003894 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003895 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003896 __ bind(deferred->exit());
3897 }
3898}
3899
3900
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003901void LCodeGen::DoMathFloor(LMathFloor* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003902 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003903 XMMRegister xmm_scratch = double_scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003904 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003905 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003906
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003907 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003908 CpuFeatureScope scope(masm(), SSE4_1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003909 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3910 // Deoptimize on negative zero.
3911 Label non_zero;
3912 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3913 __ ucomisd(input_reg, xmm_scratch);
3914 __ j(not_equal, &non_zero, Label::kNear);
3915 __ movmskpd(output_reg, input_reg);
3916 __ test(output_reg, Immediate(1));
3917 DeoptimizeIf(not_zero, instr->environment());
3918 __ bind(&non_zero);
3919 }
3920 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3921 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3922 // Overflow is signalled with minint.
3923 __ cmp(output_reg, 0x80000000u);
3924 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003925 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003926 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003927 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003928 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3929 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003930 DeoptimizeIf(parity_even, instr->environment());
3931 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003932
3933 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3934 // Check for negative zero.
3935 Label positive_sign;
3936 __ j(above, &positive_sign, Label::kNear);
3937 __ movmskpd(output_reg, input_reg);
3938 __ test(output_reg, Immediate(1));
3939 DeoptimizeIf(not_zero, instr->environment());
3940 __ Set(output_reg, Immediate(0));
3941 __ jmp(&done, Label::kNear);
3942 __ bind(&positive_sign);
3943 }
3944
3945 // Use truncating instruction (OK because input is positive).
3946 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003947 // Overflow is signalled with minint.
3948 __ cmp(output_reg, 0x80000000u);
3949 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003950 __ jmp(&done, Label::kNear);
3951
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003952 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003953 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003954 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003955 __ cvttsd2si(output_reg, Operand(input_reg));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003956 __ Cvtsi2sd(xmm_scratch, output_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003957 __ ucomisd(input_reg, xmm_scratch);
3958 __ j(equal, &done, Label::kNear);
3959 __ sub(output_reg, Immediate(1));
3960 DeoptimizeIf(overflow, instr->environment());
3961
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003962 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003963 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003964}
3965
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003966
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003967void LCodeGen::DoMathRound(LMathRound* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003968 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003969 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003970 XMMRegister input_reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003971 XMMRegister xmm_scratch = double_scratch0();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003972 XMMRegister input_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003973 ExternalReference one_half = ExternalReference::address_of_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003974 ExternalReference minus_one_half =
3975 ExternalReference::address_of_minus_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003976
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003977 Label done, round_to_zero, below_one_half, do_not_compensate;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003978 __ movsd(xmm_scratch, Operand::StaticVariable(one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003979 __ ucomisd(xmm_scratch, input_reg);
3980 __ j(above, &below_one_half);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003981
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003982 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3983 __ addsd(xmm_scratch, input_reg);
3984 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3985 // Overflow is signalled with minint.
3986 __ cmp(output_reg, 0x80000000u);
3987 __ RecordComment("D2I conversion overflow");
3988 DeoptimizeIf(equal, instr->environment());
3989 __ jmp(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003990
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003991 __ bind(&below_one_half);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003992 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003993 __ ucomisd(xmm_scratch, input_reg);
3994 __ j(below_equal, &round_to_zero);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003995
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003996 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3997 // compare and compensate.
3998 __ movsd(input_temp, input_reg); // Do not alter input_reg.
3999 __ subsd(input_temp, xmm_scratch);
4000 __ cvttsd2si(output_reg, Operand(input_temp));
4001 // Catch minint due to overflow, and to prevent overflow when compensating.
4002 __ cmp(output_reg, 0x80000000u);
4003 __ RecordComment("D2I conversion overflow");
4004 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004005
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004006 __ Cvtsi2sd(xmm_scratch, output_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004007 __ ucomisd(xmm_scratch, input_temp);
4008 __ j(equal, &done);
4009 __ sub(output_reg, Immediate(1));
4010 // No overflow because we already ruled out minint.
4011 __ jmp(&done);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004012
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004013 __ bind(&round_to_zero);
4014 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
4015 // we can ignore the difference between a result of -0 and +0.
4016 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4017 // If the sign is positive, we return +0.
4018 __ movmskpd(output_reg, input_reg);
4019 __ test(output_reg, Immediate(1));
4020 __ RecordComment("Minus zero");
4021 DeoptimizeIf(not_zero, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004022 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004023 __ Set(output_reg, Immediate(0));
4024 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004025}
4026
4027
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004028void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004029 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004030 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004031 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
4032 __ sqrtsd(input_reg, input_reg);
4033}
4034
4035
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004036void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004037 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004038 XMMRegister xmm_scratch = double_scratch0();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004039 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004040 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004041 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004042
4043 // Note that according to ECMA-262 15.8.2.13:
4044 // Math.pow(-Infinity, 0.5) == Infinity
4045 // Math.sqrt(-Infinity) == NaN
4046 Label done, sqrt;
4047 // Check base for -Infinity. According to IEEE-754, single-precision
4048 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
4049 __ mov(scratch, 0xFF800000);
4050 __ movd(xmm_scratch, scratch);
4051 __ cvtss2sd(xmm_scratch, xmm_scratch);
4052 __ ucomisd(input_reg, xmm_scratch);
4053 // Comparing -Infinity with NaN results in "unordered", which sets the
4054 // zero flag as if both were equal. However, it also sets the carry flag.
4055 __ j(not_equal, &sqrt, Label::kNear);
4056 __ j(carry, &sqrt, Label::kNear);
4057 // If input is -Infinity, return Infinity.
4058 __ xorps(input_reg, input_reg);
4059 __ subsd(input_reg, xmm_scratch);
4060 __ jmp(&done, Label::kNear);
4061
4062 // Square root.
4063 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004064 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004065 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004066 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004067 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004068}
4069
4070
4071void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004072 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004073 // Having marked this as a call, we can use any registers.
4074 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004075 ASSERT(!instr->right()->IsDoubleRegister() ||
4076 ToDoubleRegister(instr->right()).is(xmm1));
4077 ASSERT(!instr->right()->IsRegister() ||
4078 ToRegister(instr->right()).is(eax));
4079 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004080 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004082 if (exponent_type.IsSmi()) {
4083 MathPowStub stub(MathPowStub::TAGGED);
4084 __ CallStub(&stub);
4085 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004086 Label no_deopt;
4087 __ JumpIfSmi(eax, &no_deopt);
4088 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004089 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004090 __ bind(&no_deopt);
4091 MathPowStub stub(MathPowStub::TAGGED);
4092 __ CallStub(&stub);
4093 } else if (exponent_type.IsInteger32()) {
4094 MathPowStub stub(MathPowStub::INTEGER);
4095 __ CallStub(&stub);
4096 } else {
4097 ASSERT(exponent_type.IsDouble());
4098 MathPowStub stub(MathPowStub::DOUBLE);
4099 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004100 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004101}
4102
4103
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004104void LCodeGen::DoRandom(LRandom* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004105 CpuFeatureScope scope(masm(), SSE2);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004106
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004107 // Assert that the register size is indeed the size of each seed.
4108 static const int kSeedSize = sizeof(uint32_t);
4109 STATIC_ASSERT(kPointerSize == kSeedSize);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004110
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004111 // Load native context
4112 Register global_object = ToRegister(instr->global_object());
4113 Register native_context = global_object;
4114 __ mov(native_context, FieldOperand(
4115 global_object, GlobalObject::kNativeContextOffset));
4116
4117 // Load state (FixedArray of the native context's random seeds)
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004118 static const int kRandomSeedOffset =
4119 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004120 Register state = native_context;
4121 __ mov(state, FieldOperand(native_context, kRandomSeedOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004122
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004123 // Load state[0].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004124 Register state0 = ToRegister(instr->scratch());
4125 __ mov(state0, FieldOperand(state, ByteArray::kHeaderSize));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004126 // Load state[1].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004127 Register state1 = ToRegister(instr->scratch2());
4128 __ mov(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004129
4130 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004131 Register scratch3 = ToRegister(instr->scratch3());
4132 __ movzx_w(scratch3, state0);
4133 __ imul(scratch3, scratch3, 18273);
4134 __ shr(state0, 16);
4135 __ add(state0, scratch3);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004136 // Save state[0].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004137 __ mov(FieldOperand(state, ByteArray::kHeaderSize), state0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004138
4139 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004140 __ movzx_w(scratch3, state1);
4141 __ imul(scratch3, scratch3, 36969);
4142 __ shr(state1, 16);
4143 __ add(state1, scratch3);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004144 // Save state[1].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004145 __ mov(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004146
4147 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004148 Register random = state0;
4149 __ shl(random, 14);
4150 __ and_(state1, Immediate(0x3FFFF));
4151 __ add(random, state1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004152
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004153 // Convert 32 random bits in random to 0.(32 random bits) in a double
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004154 // by computing:
4155 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004156 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004157 XMMRegister scratch4 = double_scratch0();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004158 __ mov(scratch3, Immediate(0x49800000)); // 1.0 x 2^20 as single.
4159 __ movd(scratch4, scratch3);
4160 __ movd(result, random);
4161 __ cvtss2sd(scratch4, scratch4);
4162 __ xorps(result, scratch4);
4163 __ subsd(result, scratch4);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004164}
4165
4166
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004167void LCodeGen::DoMathLog(LMathLog* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004168 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004169 ASSERT(instr->value()->Equals(instr->result()));
4170 XMMRegister input_reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004171 XMMRegister xmm_scratch = double_scratch0();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004172 Label positive, done, zero;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004173 __ xorps(xmm_scratch, xmm_scratch);
4174 __ ucomisd(input_reg, xmm_scratch);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004175 __ j(above, &positive, Label::kNear);
4176 __ j(equal, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004177 ExternalReference nan =
4178 ExternalReference::address_of_canonical_non_hole_nan();
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004179 __ movsd(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004180 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004181 __ bind(&zero);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004182 ExternalReference ninf =
4183 ExternalReference::address_of_negative_infinity();
4184 __ movsd(input_reg, Operand::StaticVariable(ninf));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004185 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004186 __ bind(&positive);
4187 __ fldln2();
4188 __ sub(Operand(esp), Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004189 __ movsd(Operand(esp, 0), input_reg);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004190 __ fld_d(Operand(esp, 0));
4191 __ fyl2x();
4192 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004193 __ movsd(input_reg, Operand(esp, 0));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004194 __ add(Operand(esp), Immediate(kDoubleSize));
4195 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004196}
4197
4198
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004199void LCodeGen::DoMathExp(LMathExp* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004200 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004201 XMMRegister input = ToDoubleRegister(instr->value());
4202 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004203 XMMRegister temp0 = double_scratch0();
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004204 Register temp1 = ToRegister(instr->temp1());
4205 Register temp2 = ToRegister(instr->temp2());
4206
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004207 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004208}
4209
4210
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004211void LCodeGen::DoMathTan(LMathTan* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004212 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
danno@chromium.org59400602013-08-13 17:09:37 +00004213 // Set the context register to a GC-safe fake value. Clobbering it is
4214 // OK because this instruction is marked as a call.
4215 __ Set(esi, Immediate(0));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004216 TranscendentalCacheStub stub(TranscendentalCache::TAN,
4217 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004218 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004219}
4220
4221
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004222void LCodeGen::DoMathCos(LMathCos* instr) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004223 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
danno@chromium.org59400602013-08-13 17:09:37 +00004224 // Set the context register to a GC-safe fake value. Clobbering it is
4225 // OK because this instruction is marked as a call.
4226 __ Set(esi, Immediate(0));
whesse@chromium.org023421e2010-12-21 12:19:12 +00004227 TranscendentalCacheStub stub(TranscendentalCache::COS,
4228 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004229 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004230}
4231
4232
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004233void LCodeGen::DoMathSin(LMathSin* instr) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00004234 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
danno@chromium.org59400602013-08-13 17:09:37 +00004235 // Set the context register to a GC-safe fake value. Clobbering it is
4236 // OK because this instruction is marked as a call.
4237 __ Set(esi, Immediate(0));
whesse@chromium.org023421e2010-12-21 12:19:12 +00004238 TranscendentalCacheStub stub(TranscendentalCache::SIN,
4239 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004240 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004241}
4242
4243
danno@chromium.org160a7b02011-04-18 15:51:38 +00004244void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
4245 ASSERT(ToRegister(instr->context()).is(esi));
4246 ASSERT(ToRegister(instr->function()).is(edi));
4247 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004248
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004249 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
4250 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004251 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004252 SafepointGenerator generator(
4253 this, pointers, Safepoint::kLazyDeopt);
4254 ParameterCount count(instr->arity());
4255 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
4256 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004257 CallKnownFunction(known_function,
4258 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004259 instr->arity(),
4260 instr,
4261 CALL_AS_METHOD,
4262 EDI_CONTAINS_TARGET);
4263 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004264}
4265
4266
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004267void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004268 ASSERT(ToRegister(instr->context()).is(esi));
4269 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004270 ASSERT(ToRegister(instr->result()).is(eax));
4271
4272 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00004273 Handle<Code> ic =
4274 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004275 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004276}
4277
4278
4279void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004280 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004281 ASSERT(ToRegister(instr->result()).is(eax));
4282
4283 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004284 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4285 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004286 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004287 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004288 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004289}
4290
4291
4292void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004293 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004294 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004295 ASSERT(ToRegister(instr->result()).is(eax));
4296
4297 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004298 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004299 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004300}
4301
4302
4303void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004304 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004305 ASSERT(ToRegister(instr->result()).is(eax));
4306
4307 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004308 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4309 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004310 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004311 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004312 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004313}
4314
4315
4316void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4317 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004318 CallKnownFunction(instr->hydrogen()->target(),
4319 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004320 instr->arity(),
4321 instr,
4322 CALL_AS_FUNCTION,
4323 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004324}
4325
4326
4327void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004328 ASSERT(ToRegister(instr->context()).is(esi));
4329 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004330 ASSERT(ToRegister(instr->result()).is(eax));
4331
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004332 // No cell in ebx for construct type feedback in optimized code
4333 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
4334 __ mov(ebx, Immediate(undefined_value));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004335 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004336 __ Set(eax, Immediate(instr->arity()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004337 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004338}
4339
4340
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004341void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4342 ASSERT(ToRegister(instr->context()).is(esi));
4343 ASSERT(ToRegister(instr->constructor()).is(edi));
4344 ASSERT(ToRegister(instr->result()).is(eax));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004345
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004346 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004347 __ mov(ebx, instr->hydrogen()->property_cell());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004348 ElementsKind kind = instr->hydrogen()->elements_kind();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004349 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00004350 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004351 ? DISABLE_ALLOCATION_SITES
4352 : DONT_OVERRIDE;
4353 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004354
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004355 if (instr->arity() == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004356 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004357 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4358 } else if (instr->arity() == 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00004359 Label done;
4360 if (IsFastPackedElementsKind(kind)) {
4361 Label packed_case;
4362 // We might need a change here
4363 // look at the first argument
4364 __ mov(ecx, Operand(esp, 0));
4365 __ test(ecx, ecx);
4366 __ j(zero, &packed_case);
4367
4368 ElementsKind holey_kind = GetHoleyElementsKind(kind);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004369 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
4370 override_mode);
danno@chromium.org41728482013-06-12 22:31:22 +00004371 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4372 __ jmp(&done);
4373 __ bind(&packed_case);
4374 }
4375
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004376 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004377 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.org41728482013-06-12 22:31:22 +00004378 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004379 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004380 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004381 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4382 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004383}
4384
4385
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004386void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004387 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004388}
4389
4390
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004391void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
4392 Register function = ToRegister(instr->function());
4393 Register code_object = ToRegister(instr->code_object());
4394 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
4395 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
4396}
4397
4398
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004399void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4400 Register result = ToRegister(instr->result());
4401 Register base = ToRegister(instr->base_object());
4402 __ lea(result, Operand(base, instr->offset()));
4403}
4404
4405
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004406void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004407 Representation representation = instr->representation();
4408
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004409 HObjectAccess access = instr->hydrogen()->access();
4410 int offset = access.offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004411
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004412 if (access.IsExternalMemory()) {
4413 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4414 MemOperand operand = instr->object()->IsConstantOperand()
4415 ? MemOperand::StaticVariable(
4416 ToExternalReference(LConstantOperand::cast(instr->object())))
4417 : MemOperand(ToRegister(instr->object()), offset);
4418 if (instr->value()->IsConstantOperand()) {
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004419 ASSERT(!representation.IsByte());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004420 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004421 __ mov(operand, Immediate(ToInteger32(operand_value)));
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004422 } else {
4423 Register value = ToRegister(instr->value());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004424 if (representation.IsByte()) {
4425 __ mov_b(operand, value);
4426 } else {
4427 __ mov(operand, value);
4428 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004429 }
4430 return;
4431 }
4432
4433 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004434 Handle<Map> transition = instr->transition();
4435
danno@chromium.orgf005df62013-04-30 16:36:45 +00004436 if (FLAG_track_fields && representation.IsSmi()) {
4437 if (instr->value()->IsConstantOperand()) {
4438 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004439 if (!IsSmi(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004440 DeoptimizeIf(no_condition, instr->environment());
4441 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00004442 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004443 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
4444 if (instr->value()->IsConstantOperand()) {
4445 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4446 if (IsInteger32(operand_value)) {
4447 DeoptimizeIf(no_condition, instr->environment());
4448 }
4449 } else {
4450 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
4451 Register value = ToRegister(instr->value());
4452 __ test(value, Immediate(kSmiTagMask));
4453 DeoptimizeIf(zero, instr->environment());
4454 }
4455 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004456 } else if (FLAG_track_double_fields && representation.IsDouble()) {
4457 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004458 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004459 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4460 if (CpuFeatures::IsSupported(SSE2)) {
4461 CpuFeatureScope scope(masm(), SSE2);
4462 XMMRegister value = ToDoubleRegister(instr->value());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004463 __ movsd(FieldOperand(object, offset), value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004464 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00004465 X87Register value = ToX87Register(instr->value());
4466 X87Mov(FieldOperand(object, offset), value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004467 }
4468 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00004469 }
4470
danno@chromium.orgf005df62013-04-30 16:36:45 +00004471 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004472 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004473 __ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004474 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004475 Register temp = ToRegister(instr->temp());
4476 Register temp_map = ToRegister(instr->temp_map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004477 __ mov(temp_map, transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004478 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4479 // Update the write barrier for the map field.
4480 __ RecordWriteField(object,
4481 HeapObject::kMapOffset,
4482 temp_map,
4483 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004484 GetSaveFPRegsMode(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004485 OMIT_REMEMBERED_SET,
4486 OMIT_SMI_CHECK);
4487 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004488 }
4489
4490 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004491 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004492 instr->hydrogen()->value()->IsHeapObject()
4493 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004494
4495 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004496 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004497 write_register = ToRegister(instr->temp());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004498 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004499 }
4500
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004501 MemOperand operand = FieldOperand(write_register, offset);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004502 if (instr->value()->IsConstantOperand()) {
4503 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004504 if (operand_value->IsRegister()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004505 Register value = ToRegister(operand_value);
4506 if (representation.IsByte()) {
4507 __ mov_b(operand, value);
4508 } else {
4509 __ mov(operand, value);
4510 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004511 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004512 Handle<Object> handle_value = ToHandle(operand_value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004513 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004514 __ mov(operand, handle_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004515 }
4516 } else {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004517 Register value = ToRegister(instr->value());
4518 if (representation.IsByte()) {
4519 __ mov_b(operand, value);
4520 } else {
4521 __ mov(operand, value);
4522 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004523 }
4524
4525 if (instr->hydrogen()->NeedsWriteBarrier()) {
4526 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004527 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004528 // Update the write barrier for the object for in-object properties.
4529 __ RecordWriteField(write_register,
4530 offset,
4531 value,
4532 temp,
4533 GetSaveFPRegsMode(),
4534 EMIT_REMEMBERED_SET,
4535 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004536 }
4537}
4538
4539
4540void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004541 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004542 ASSERT(ToRegister(instr->object()).is(edx));
4543 ASSERT(ToRegister(instr->value()).is(eax));
4544
4545 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004546 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004547 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4548 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004549 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004550}
4551
4552
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004553void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
4554 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4555 Label done;
4556 __ j(NegateCondition(cc), &done, Label::kNear);
4557 __ int3();
4558 __ bind(&done);
4559 } else {
4560 DeoptimizeIf(cc, check->environment());
4561 }
4562}
4563
4564
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004565void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004566 if (instr->hydrogen()->skip_check() && !FLAG_debug_code) return;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004567
danno@chromium.orgb6451162011-08-17 14:33:23 +00004568 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004569 Immediate immediate =
4570 ToImmediate(LConstantOperand::cast(instr->index()),
4571 instr->hydrogen()->length()->representation());
4572 __ cmp(ToOperand(instr->length()), immediate);
4573 Condition condition =
4574 instr->hydrogen()->allow_equality() ? below : below_equal;
4575 ApplyCheckIf(condition, instr);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004576 } else {
4577 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004578 Condition condition =
4579 instr->hydrogen()->allow_equality() ? above : above_equal;
4580 ApplyCheckIf(condition, instr);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004581 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004582}
4583
4584
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004585void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004586 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004587 LOperand* key = instr->key();
4588 if (!key->IsConstantOperand() &&
4589 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4590 elements_kind)) {
4591 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004592 }
4593 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004594 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004595 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004596 instr->hydrogen()->key()->representation(),
4597 elements_kind,
4598 0,
4599 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004600 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004601 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4602 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004603 XMMRegister xmm_scratch = double_scratch0();
4604 __ cvtsd2ss(xmm_scratch, ToDoubleRegister(instr->value()));
4605 __ movss(operand, xmm_scratch);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004606 } else {
4607 __ fld(0);
4608 __ fstp_s(operand);
4609 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004610 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004611 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4612 CpuFeatureScope scope(masm(), SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004613 __ movsd(operand, ToDoubleRegister(instr->value()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004614 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00004615 X87Mov(operand, ToX87Register(instr->value()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004616 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004617 } else {
4618 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004619 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004620 case EXTERNAL_PIXEL_ELEMENTS:
4621 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4622 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004623 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004624 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004625 case EXTERNAL_SHORT_ELEMENTS:
4626 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004627 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004628 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004629 case EXTERNAL_INT_ELEMENTS:
4630 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004631 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004632 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004633 case EXTERNAL_FLOAT_ELEMENTS:
4634 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004635 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004636 case FAST_ELEMENTS:
4637 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004638 case FAST_HOLEY_SMI_ELEMENTS:
4639 case FAST_HOLEY_ELEMENTS:
4640 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004641 case DICTIONARY_ELEMENTS:
4642 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004643 UNREACHABLE();
4644 break;
4645 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004646 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004647}
4648
4649
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004650void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004651 ExternalReference canonical_nan_reference =
4652 ExternalReference::address_of_canonical_non_hole_nan();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004653 Operand double_store_operand = BuildFastArrayOperand(
4654 instr->elements(),
4655 instr->key(),
4656 instr->hydrogen()->key()->representation(),
4657 FAST_DOUBLE_ELEMENTS,
4658 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4659 instr->additional_index());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004660
4661 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4662 CpuFeatureScope scope(masm(), SSE2);
4663 XMMRegister value = ToDoubleRegister(instr->value());
4664
4665 if (instr->NeedsCanonicalization()) {
4666 Label have_value;
4667
4668 __ ucomisd(value, value);
4669 __ j(parity_odd, &have_value); // NaN.
4670
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004671 __ movsd(value, Operand::StaticVariable(canonical_nan_reference));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004672 __ bind(&have_value);
4673 }
4674
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004675 __ movsd(double_store_operand, value);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004676 } else {
4677 // Can't use SSE2 in the serializer
4678 if (instr->hydrogen()->IsConstantHoleStore()) {
4679 // This means we should store the (double) hole. No floating point
4680 // registers required.
4681 double nan_double = FixedDoubleArray::hole_nan_as_double();
4682 uint64_t int_val = BitCast<uint64_t, double>(nan_double);
4683 int32_t lower = static_cast<int32_t>(int_val);
4684 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
4685
4686 __ mov(double_store_operand, Immediate(lower));
4687 Operand double_store_operand2 = BuildFastArrayOperand(
4688 instr->elements(),
4689 instr->key(),
4690 instr->hydrogen()->key()->representation(),
4691 FAST_DOUBLE_ELEMENTS,
4692 FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
4693 instr->additional_index());
4694 __ mov(double_store_operand2, Immediate(upper));
4695 } else {
4696 Label no_special_nan_handling;
danno@chromium.org169691d2013-07-15 08:01:13 +00004697 X87Register value = ToX87Register(instr->value());
4698 X87Fxch(value);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004699
4700 if (instr->NeedsCanonicalization()) {
4701 __ fld(0);
4702 __ fld(0);
4703 __ FCmp();
4704
4705 __ j(parity_odd, &no_special_nan_handling);
4706 __ sub(esp, Immediate(kDoubleSize));
4707 __ fst_d(MemOperand(esp, 0));
4708 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4709 Immediate(kHoleNanUpper32));
4710 __ add(esp, Immediate(kDoubleSize));
4711 Label canonicalize;
4712 __ j(not_equal, &canonicalize);
4713 __ jmp(&no_special_nan_handling);
4714 __ bind(&canonicalize);
4715 __ fstp(0);
4716 __ fld_d(Operand::StaticVariable(canonical_nan_reference));
4717 }
4718
4719 __ bind(&no_special_nan_handling);
4720 __ fst_d(double_store_operand);
4721 }
4722 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004723}
4724
4725
4726void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004727 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004728 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4729
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004730 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004731 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004732 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004733 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004734 FAST_ELEMENTS,
4735 FixedArray::kHeaderSize - kHeapObjectTag,
4736 instr->additional_index());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004737 if (instr->value()->IsRegister()) {
4738 __ mov(operand, ToRegister(instr->value()));
4739 } else {
4740 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004741 if (IsSmi(operand_value)) {
4742 Immediate immediate = ToImmediate(operand_value, Representation::Smi());
4743 __ mov(operand, immediate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004744 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004745 ASSERT(!IsInteger32(operand_value));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004746 Handle<Object> handle_value = ToHandle(operand_value);
4747 __ mov(operand, handle_value);
4748 }
4749 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004750
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004751 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004752 ASSERT(instr->value()->IsRegister());
4753 Register value = ToRegister(instr->value());
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004754 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004755 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004756 instr->hydrogen()->value()->IsHeapObject()
4757 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004758 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004759 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004760 __ RecordWrite(elements,
4761 key,
4762 value,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004763 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004764 EMIT_REMEMBERED_SET,
4765 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004766 }
4767}
4768
4769
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004770void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4771 // By cases...external, fast-double, fast
4772 if (instr->is_external()) {
4773 DoStoreKeyedExternalArray(instr);
4774 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4775 DoStoreKeyedFixedDoubleArray(instr);
4776 } else {
4777 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004778 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004779}
4780
4781
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004782void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004783 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004784 ASSERT(ToRegister(instr->object()).is(edx));
4785 ASSERT(ToRegister(instr->key()).is(ecx));
4786 ASSERT(ToRegister(instr->value()).is(eax));
4787
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004788 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004789 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4790 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004791 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004792}
4793
4794
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004795void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4796 Register object = ToRegister(instr->object());
4797 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004798 Label no_memento_found;
4799 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004800 DeoptimizeIf(equal, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004801 __ bind(&no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004802}
4803
4804
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004805void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4806 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004807
4808 Handle<Map> from_map = instr->original_map();
4809 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004810 ElementsKind from_kind = instr->from_kind();
4811 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004812
4813 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004814 bool is_simple_map_transition =
4815 IsSimpleMapChangeTransition(from_kind, to_kind);
4816 Label::Distance branch_distance =
4817 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004818 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004819 __ j(not_equal, &not_applicable, branch_distance);
4820 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004821 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004822 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004823 Immediate(to_map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004824 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004825 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004826 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004827 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004828 kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004829 } else {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004830 PushSafepointRegistersScope scope(this);
4831 if (!object_reg.is(eax)) {
4832 __ push(object_reg);
4833 }
4834 LoadContextFromDeferred(instr->context());
4835 if (!object_reg.is(eax)) {
4836 __ pop(eax);
4837 }
4838 __ mov(ebx, to_map);
4839 TransitionElementsKindStub stub(from_kind, to_kind);
4840 __ CallStub(&stub);
4841 RecordSafepointWithRegisters(
4842 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004843 }
4844 __ bind(&not_applicable);
4845}
4846
4847
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004848void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004849 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004850 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004851 DeferredStringCharCodeAt(LCodeGen* codegen,
4852 LStringCharCodeAt* instr,
4853 const X87Stack& x87_stack)
4854 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004855 virtual void Generate() V8_OVERRIDE {
4856 codegen()->DoDeferredStringCharCodeAt(instr_);
4857 }
4858 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004859 private:
4860 LStringCharCodeAt* instr_;
4861 };
4862
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004863 DeferredStringCharCodeAt* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004864 new(zone()) DeferredStringCharCodeAt(this, instr, x87_stack_);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004865
erikcorry0ad885c2011-11-21 13:51:57 +00004866 StringCharLoadGenerator::Generate(masm(),
4867 factory(),
4868 ToRegister(instr->string()),
4869 ToRegister(instr->index()),
4870 ToRegister(instr->result()),
4871 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004872 __ bind(deferred->exit());
4873}
4874
4875
4876void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4877 Register string = ToRegister(instr->string());
4878 Register result = ToRegister(instr->result());
4879
4880 // TODO(3095996): Get rid of this. For now, we need to make the
4881 // result register contain a valid pointer because it is already
4882 // contained in the register pointer map.
4883 __ Set(result, Immediate(0));
4884
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004885 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004886 __ push(string);
4887 // Push the index as a smi. This is safe because of the checks in
4888 // DoStringCharCodeAt above.
4889 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4890 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004891 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->index()),
4892 Representation::Smi());
4893 __ push(immediate);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004894 } else {
4895 Register index = ToRegister(instr->index());
4896 __ SmiTag(index);
4897 __ push(index);
4898 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004899 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4900 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004901 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004902 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004903 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004904}
4905
4906
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004907void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004908 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004909 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004910 DeferredStringCharFromCode(LCodeGen* codegen,
4911 LStringCharFromCode* instr,
4912 const X87Stack& x87_stack)
4913 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004914 virtual void Generate() V8_OVERRIDE {
4915 codegen()->DoDeferredStringCharFromCode(instr_);
4916 }
4917 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004918 private:
4919 LStringCharFromCode* instr_;
4920 };
4921
4922 DeferredStringCharFromCode* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004923 new(zone()) DeferredStringCharFromCode(this, instr, x87_stack_);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004924
4925 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4926 Register char_code = ToRegister(instr->char_code());
4927 Register result = ToRegister(instr->result());
4928 ASSERT(!char_code.is(result));
4929
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004930 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004931 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004932 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004933 __ mov(result, FieldOperand(result,
4934 char_code, times_pointer_size,
4935 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004936 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004937 __ j(equal, deferred->entry());
4938 __ bind(deferred->exit());
4939}
4940
4941
4942void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4943 Register char_code = ToRegister(instr->char_code());
4944 Register result = ToRegister(instr->result());
4945
4946 // TODO(3095996): Get rid of this. For now, we need to make the
4947 // result register contain a valid pointer because it is already
4948 // contained in the register pointer map.
4949 __ Set(result, Immediate(0));
4950
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004951 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004952 __ SmiTag(char_code);
4953 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004954 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004955 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004956}
4957
4958
danno@chromium.org160a7b02011-04-18 15:51:38 +00004959void LCodeGen::DoStringAdd(LStringAdd* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004960 EmitPushTaggedOperand(instr->left());
4961 EmitPushTaggedOperand(instr->right());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004962 StringAddStub stub(instr->hydrogen()->flags());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004963 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004964}
4965
4966
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004967void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004968 LOperand* input = instr->value();
4969 LOperand* output = instr->result();
4970 ASSERT(input->IsRegister() || input->IsStackSlot());
4971 ASSERT(output->IsDoubleRegister());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004972 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004973 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004974 __ Cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004975 } else if (input->IsRegister()) {
4976 Register input_reg = ToRegister(input);
4977 __ push(input_reg);
4978 X87Mov(ToX87Register(output), Operand(esp, 0), kX87IntOperand);
4979 __ pop(input_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004980 } else {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004981 X87Mov(ToX87Register(output), ToOperand(input), kX87IntOperand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004982 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004983}
4984
4985
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004986void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4987 Register input = ToRegister(instr->value());
4988 __ SmiTag(input);
4989 if (!instr->hydrogen()->value()->HasRange() ||
4990 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4991 DeoptimizeIf(overflow, instr->environment());
4992 }
4993}
4994
4995
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004996void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004997 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004998 LOperand* output = instr->result();
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004999 if (CpuFeatures::IsSupported(SSE2)) {
5000 CpuFeatureScope scope(masm(), SSE2);
5001 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005002
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00005003 __ LoadUint32(ToDoubleRegister(output),
5004 ToRegister(input),
5005 ToDoubleRegister(temp));
5006 } else {
5007 X87Register res = ToX87Register(output);
5008 X87PrepareToWrite(res);
5009 __ LoadUint32NoSSE2(ToRegister(input));
5010 X87CommitWrite(res);
5011 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005012}
5013
5014
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00005015void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
5016 Register input = ToRegister(instr->value());
5017 if (!instr->hydrogen()->value()->HasRange() ||
5018 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
5019 __ test(input, Immediate(0xc0000000));
5020 DeoptimizeIf(not_zero, instr->environment());
5021 }
5022 __ SmiTag(input);
5023}
5024
5025
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005027 class DeferredNumberTagI V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005029 DeferredNumberTagI(LCodeGen* codegen,
5030 LNumberTagI* instr,
5031 const X87Stack& x87_stack)
5032 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005033 virtual void Generate() V8_OVERRIDE {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005034 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005035 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005036 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005037 private:
5038 LNumberTagI* instr_;
5039 };
5040
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005041 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005042 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5043 Register reg = ToRegister(input);
5044
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005045 DeferredNumberTagI* deferred =
5046 new(zone()) DeferredNumberTagI(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005047 __ SmiTag(reg);
5048 __ j(overflow, deferred->entry());
5049 __ bind(deferred->exit());
5050}
5051
5052
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005053void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005054 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005055 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005056 DeferredNumberTagU(LCodeGen* codegen,
5057 LNumberTagU* instr,
5058 const X87Stack& x87_stack)
5059 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005060 virtual void Generate() V8_OVERRIDE {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005061 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005062 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005063 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005064 private:
5065 LNumberTagU* instr_;
5066 };
5067
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005068 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005069 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5070 Register reg = ToRegister(input);
5071
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005072 DeferredNumberTagU* deferred =
5073 new(zone()) DeferredNumberTagU(this, instr, x87_stack_);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005074 __ cmp(reg, Immediate(Smi::kMaxValue));
5075 __ j(above, deferred->entry());
5076 __ SmiTag(reg);
5077 __ bind(deferred->exit());
5078}
5079
5080
5081void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
5082 LOperand* value,
5083 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005084 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005085 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005086 Register tmp = reg.is(eax) ? ecx : eax;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005087 XMMRegister xmm_scratch = double_scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005088
5089 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005090 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005091
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005092 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005093
5094 if (signedness == SIGNED_INT32) {
5095 // There was overflow, so bits 30 and 31 of the original integer
5096 // disagree. Try to allocate a heap number in new space and store
5097 // the value in there. If that fails, call the runtime system.
5098 __ SmiUntag(reg);
5099 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005100 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005101 CpuFeatureScope feature_scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005102 __ Cvtsi2sd(xmm_scratch, Operand(reg));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005103 } else {
5104 __ push(reg);
5105 __ fild_s(Operand(esp, 0));
5106 __ pop(reg);
5107 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005108 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005109 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005110 CpuFeatureScope feature_scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005111 __ LoadUint32(xmm_scratch, reg,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005112 ToDoubleRegister(LNumberTagU::cast(instr)->temp()));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005113 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005114 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
5115 // int manually.
5116 __ push(Immediate(0));
5117 __ push(reg);
5118 __ fild_d(Operand(esp, 0));
5119 __ pop(reg);
5120 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005121 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005122 }
5123
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005124 if (FLAG_inline_new) {
5125 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005126 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127 }
5128
5129 // Slow case: Call the runtime system to do the number allocation.
5130 __ bind(&slow);
5131
5132 // TODO(3095996): Put a valid pointer value in the stack slot where the result
5133 // register is stored, as this register is in the pointer map, but contains an
5134 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005135 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005136 // NumberTagI and NumberTagD use the context from the frame, rather than
5137 // the environment's HContext or HInlinedContext value.
5138 // They only call Runtime::kAllocateHeapNumber.
5139 // The corresponding HChange instructions are added in a phase that does
5140 // not have easy access to the local context.
5141 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5142 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
5143 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005144 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 if (!reg.is(eax)) __ mov(reg, eax);
5146
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005147 // Done. Put the value in xmm_scratch into the value of the allocated heap
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005148 // number.
5149 __ bind(&done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005150 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005151 CpuFeatureScope feature_scope(masm(), SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005152 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm_scratch);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005153 } else {
5154 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
5155 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005156 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005157}
5158
5159
5160void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005161 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005162 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005163 DeferredNumberTagD(LCodeGen* codegen,
5164 LNumberTagD* instr,
5165 const X87Stack& x87_stack)
5166 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005167 virtual void Generate() V8_OVERRIDE {
5168 codegen()->DoDeferredNumberTagD(instr_);
5169 }
5170 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005171 private:
5172 LNumberTagD* instr_;
5173 };
5174
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005175 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005176
danno@chromium.org169691d2013-07-15 08:01:13 +00005177 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
5178 if (!use_sse2) {
5179 // Put the value to the top of stack
5180 X87Register src = ToX87Register(instr->value());
5181 X87LoadForUsage(src);
5182 }
5183
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005184 DeferredNumberTagD* deferred =
5185 new(zone()) DeferredNumberTagD(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005186 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005187 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005188 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
5189 } else {
5190 __ jmp(deferred->entry());
5191 }
5192 __ bind(deferred->exit());
danno@chromium.org169691d2013-07-15 08:01:13 +00005193 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005194 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005195 XMMRegister input_reg = ToDoubleRegister(instr->value());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005196 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005197 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00005198 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005199 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005200}
5201
5202
5203void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
5204 // TODO(3095996): Get rid of this. For now, we need to make the
5205 // result register contain a valid pointer because it is already
5206 // contained in the register pointer map.
5207 Register reg = ToRegister(instr->result());
5208 __ Set(reg, Immediate(0));
5209
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005210 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005211 // NumberTagI and NumberTagD use the context from the frame, rather than
5212 // the environment's HContext or HInlinedContext value.
5213 // They only call Runtime::kAllocateHeapNumber.
5214 // The corresponding HChange instructions are added in a phase that does
5215 // not have easy access to the local context.
5216 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5217 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005218 RecordSafepointWithRegisters(
5219 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005220 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005221}
5222
5223
5224void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005225 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5227 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
5228 __ SmiTag(ToRegister(input));
5229}
5230
5231
5232void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005233 LOperand* input = instr->value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005234 Register result = ToRegister(input);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005235 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5236 if (instr->needs_check()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005237 __ test(result, Immediate(kSmiTagMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005238 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005239 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005240 __ AssertSmi(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005242 __ SmiUntag(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005243}
5244
5245
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005246void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
5247 Register temp_reg,
danno@chromium.org169691d2013-07-15 08:01:13 +00005248 X87Register res_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005249 bool can_convert_undefined_to_nan,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005250 bool deoptimize_on_minus_zero,
5251 LEnvironment* env,
5252 NumberUntagDMode mode) {
5253 Label load_smi, done;
5254
danno@chromium.org169691d2013-07-15 08:01:13 +00005255 X87PrepareToWrite(res_reg);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005256 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005257 // Smi check.
5258 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
5259
5260 // Heap number map check.
5261 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5262 factory()->heap_number_map());
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005263 if (!can_convert_undefined_to_nan) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005264 DeoptimizeIf(not_equal, env);
5265 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005266 Label heap_number, convert;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005267 __ j(equal, &heap_number, Label::kNear);
5268
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005269 // Convert undefined (or hole) to NaN.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005270 __ cmp(input_reg, factory()->undefined_value());
5271 DeoptimizeIf(not_equal, env);
5272
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005273 __ bind(&convert);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005274 ExternalReference nan =
5275 ExternalReference::address_of_canonical_non_hole_nan();
5276 __ fld_d(Operand::StaticVariable(nan));
5277 __ jmp(&done, Label::kNear);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005278
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005279 __ bind(&heap_number);
5280 }
5281 // Heap number to x87 conversion.
5282 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5283 if (deoptimize_on_minus_zero) {
5284 __ fldz();
5285 __ FCmp();
5286 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5287 __ j(not_zero, &done, Label::kNear);
5288
5289 // Use general purpose registers to check if we have -0.0
5290 __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5291 __ test(temp_reg, Immediate(HeapNumber::kSignMask));
5292 __ j(zero, &done, Label::kNear);
5293
5294 // Pop FPU stack before deoptimizing.
5295 __ fstp(0);
5296 DeoptimizeIf(not_zero, env);
5297 }
5298 __ jmp(&done, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005299 } else {
5300 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
5301 }
5302
5303 __ bind(&load_smi);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005304 // Clobbering a temp is faster than re-tagging the
5305 // input register since we avoid dependencies.
5306 __ mov(temp_reg, input_reg);
5307 __ SmiUntag(temp_reg); // Untag smi before converting to float.
5308 __ push(temp_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005309 __ fild_s(Operand(esp, 0));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005310 __ add(esp, Immediate(kPointerSize));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005311 __ bind(&done);
danno@chromium.org169691d2013-07-15 08:01:13 +00005312 X87CommitWrite(res_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005313}
5314
5315
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005316void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005317 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005318 XMMRegister result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005319 bool can_convert_undefined_to_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005320 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005321 LEnvironment* env,
5322 NumberUntagDMode mode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005323 Label convert, load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005324
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005325 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005326 // Smi check.
5327 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005328
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005329 // Heap number map check.
5330 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5331 factory()->heap_number_map());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005332 if (can_convert_undefined_to_nan) {
5333 __ j(not_equal, &convert, Label::kNear);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005334 } else {
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005335 DeoptimizeIf(not_equal, env);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005336 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005337
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005338 // Heap number to XMM conversion.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005339 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005340
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005341 if (deoptimize_on_minus_zero) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005342 XMMRegister xmm_scratch = double_scratch0();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005343 __ xorps(xmm_scratch, xmm_scratch);
5344 __ ucomisd(result_reg, xmm_scratch);
5345 __ j(not_zero, &done, Label::kNear);
5346 __ movmskpd(temp_reg, result_reg);
5347 __ test_b(temp_reg, 1);
5348 DeoptimizeIf(not_zero, env);
5349 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005350 __ jmp(&done, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005351
5352 if (can_convert_undefined_to_nan) {
5353 __ bind(&convert);
5354
5355 // Convert undefined (and hole) to NaN.
5356 __ cmp(input_reg, factory()->undefined_value());
5357 DeoptimizeIf(not_equal, env);
5358
5359 ExternalReference nan =
5360 ExternalReference::address_of_canonical_non_hole_nan();
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005361 __ movsd(result_reg, Operand::StaticVariable(nan));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005362 __ jmp(&done, Label::kNear);
5363 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005364 } else {
5365 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005366 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005367
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005368 __ bind(&load_smi);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005369 // Smi to XMM conversion. Clobbering a temp is faster than re-tagging the
5370 // input register since we avoid dependencies.
5371 __ mov(temp_reg, input_reg);
5372 __ SmiUntag(temp_reg); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005373 __ Cvtsi2sd(result_reg, Operand(temp_reg));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005374 __ bind(&done);
5375}
5376
5377
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005378void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005379 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005380
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005381 if (instr->truncating()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005382 Label no_heap_number, check_bools, check_false;
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005383
5384 // Heap number map check.
5385 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5386 factory()->heap_number_map());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005387 __ j(not_equal, &no_heap_number, Label::kNear);
5388 __ TruncateHeapNumberToI(input_reg, input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005389 __ jmp(done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005390
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005391 __ bind(&no_heap_number);
5392 // Check for Oddballs. Undefined/False is converted to zero and True to one
5393 // for truncating conversions.
5394 __ cmp(input_reg, factory()->undefined_value());
5395 __ j(not_equal, &check_bools, Label::kNear);
5396 __ Set(input_reg, Immediate(0));
5397 __ jmp(done);
5398
5399 __ bind(&check_bools);
5400 __ cmp(input_reg, factory()->true_value());
5401 __ j(not_equal, &check_false, Label::kNear);
5402 __ Set(input_reg, Immediate(1));
5403 __ jmp(done);
5404
5405 __ bind(&check_false);
5406 __ cmp(input_reg, factory()->false_value());
5407 __ RecordComment("Deferred TaggedToI: cannot truncate");
5408 DeoptimizeIf(not_equal, instr->environment());
5409 __ Set(input_reg, Immediate(0));
5410 __ jmp(done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005411 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005412 Label bailout;
5413 XMMRegister scratch = (instr->temp() != NULL)
5414 ? ToDoubleRegister(instr->temp())
5415 : no_xmm_reg;
5416 __ TaggedToI(input_reg, input_reg, scratch,
5417 instr->hydrogen()->GetMinusZeroMode(), &bailout);
5418 __ jmp(done);
5419 __ bind(&bailout);
5420 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005421 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005422}
5423
5424
5425void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005426 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005427 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005428 DeferredTaggedToI(LCodeGen* codegen,
5429 LTaggedToI* instr,
5430 const X87Stack& x87_stack)
5431 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005432 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005433 codegen()->DoDeferredTaggedToI(instr_, done());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005434 }
5435 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005436 private:
5437 LTaggedToI* instr_;
5438 };
5439
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005440 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005441 ASSERT(input->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005442 Register input_reg = ToRegister(input);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005443 ASSERT(input_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005444
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005445 if (instr->hydrogen()->value()->representation().IsSmi()) {
5446 __ SmiUntag(input_reg);
5447 } else {
5448 DeferredTaggedToI* deferred =
5449 new(zone()) DeferredTaggedToI(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005450
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005451 __ JumpIfNotSmi(input_reg, deferred->entry());
5452 __ SmiUntag(input_reg);
5453 __ bind(deferred->exit());
5454 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005455}
5456
5457
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005458void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005459 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005460 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005461 LOperand* temp = instr->temp();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005462 ASSERT(temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005463 LOperand* result = instr->result();
5464 ASSERT(result->IsDoubleRegister());
5465
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005466 Register input_reg = ToRegister(input);
5467 bool deoptimize_on_minus_zero =
5468 instr->hydrogen()->deoptimize_on_minus_zero();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005469 Register temp_reg = ToRegister(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005470
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005471 HValue* value = instr->hydrogen()->value();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005472 NumberUntagDMode mode = value->representation().IsSmi()
5473 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005474
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005475 if (CpuFeatures::IsSupported(SSE2)) {
5476 CpuFeatureScope scope(masm(), SSE2);
5477 XMMRegister result_reg = ToDoubleRegister(result);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005478 EmitNumberUntagD(input_reg,
5479 temp_reg,
5480 result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005481 instr->hydrogen()->can_convert_undefined_to_nan(),
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005482 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005483 instr->environment(),
5484 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005485 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005486 EmitNumberUntagDNoSSE2(input_reg,
5487 temp_reg,
danno@chromium.org169691d2013-07-15 08:01:13 +00005488 ToX87Register(instr->result()),
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005489 instr->hydrogen()->can_convert_undefined_to_nan(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005490 deoptimize_on_minus_zero,
5491 instr->environment(),
5492 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005493 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005494}
5495
5496
5497void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005498 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005499 ASSERT(input->IsDoubleRegister());
5500 LOperand* result = instr->result();
5501 ASSERT(result->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005502 Register result_reg = ToRegister(result);
5503
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005504 if (instr->truncating()) {
5505 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5506 CpuFeatureScope scope(masm(), SSE2);
5507 XMMRegister input_reg = ToDoubleRegister(input);
5508 __ TruncateDoubleToI(result_reg, input_reg);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005509 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005510 X87Register input_reg = ToX87Register(input);
5511 X87Fxch(input_reg);
5512 __ TruncateX87TOSToI(result_reg);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005513 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005514 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005515 Label bailout, done;
5516 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5517 CpuFeatureScope scope(masm(), SSE2);
5518 XMMRegister input_reg = ToDoubleRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005519 XMMRegister xmm_scratch = double_scratch0();
5520 __ DoubleToI(result_reg, input_reg, xmm_scratch,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005521 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005522 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005523 X87Register input_reg = ToX87Register(input);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005524 X87Fxch(input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005525 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
5526 &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005527 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005528 __ jmp(&done, Label::kNear);
5529 __ bind(&bailout);
5530 DeoptimizeIf(no_condition, instr->environment());
5531 __ bind(&done);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005532 }
5533}
5534
5535
5536void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5537 LOperand* input = instr->value();
5538 ASSERT(input->IsDoubleRegister());
5539 LOperand* result = instr->result();
5540 ASSERT(result->IsRegister());
5541 Register result_reg = ToRegister(result);
5542
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005543 Label bailout, done;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005544 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5545 CpuFeatureScope scope(masm(), SSE2);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005546 XMMRegister input_reg = ToDoubleRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005547 XMMRegister xmm_scratch = double_scratch0();
5548 __ DoubleToI(result_reg, input_reg, xmm_scratch,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005549 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005550 } else {
5551 X87Register input_reg = ToX87Register(input);
5552 X87Fxch(input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005553 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
5554 &bailout, Label::kNear);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005555 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005556 __ jmp(&done, Label::kNear);
5557 __ bind(&bailout);
5558 DeoptimizeIf(no_condition, instr->environment());
5559 __ bind(&done);
5560
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005561 __ SmiTag(result_reg);
5562 DeoptimizeIf(overflow, instr->environment());
5563}
5564
5565
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005566void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005567 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005568 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005569 DeoptimizeIf(not_zero, instr->environment());
5570}
5571
5572
5573void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005574 if (!instr->hydrogen()->value()->IsHeapObject()) {
5575 LOperand* input = instr->value();
5576 __ test(ToOperand(input), Immediate(kSmiTagMask));
5577 DeoptimizeIf(zero, instr->environment());
5578 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005579}
5580
5581
5582void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005583 Register input = ToRegister(instr->value());
5584 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005585
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005586 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005587
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005588 if (instr->hydrogen()->is_interval_check()) {
5589 InstanceType first;
5590 InstanceType last;
5591 instr->hydrogen()->GetCheckInterval(&first, &last);
5592
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005593 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5594 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005595
5596 // If there is only one type in the interval check for equality.
5597 if (first == last) {
5598 DeoptimizeIf(not_equal, instr->environment());
5599 } else {
5600 DeoptimizeIf(below, instr->environment());
5601 // Omit check for the last type.
5602 if (last != LAST_TYPE) {
5603 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5604 static_cast<int8_t>(last));
5605 DeoptimizeIf(above, instr->environment());
5606 }
5607 }
5608 } else {
5609 uint8_t mask;
5610 uint8_t tag;
5611 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5612
5613 if (IsPowerOf2(mask)) {
5614 ASSERT(tag == 0 || IsPowerOf2(tag));
5615 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5616 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5617 } else {
5618 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5619 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005620 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005621 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005622 }
5623 }
5624}
5625
5626
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005627void LCodeGen::DoCheckValue(LCheckValue* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005628 Handle<HeapObject> object = instr->hydrogen()->object().handle();
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005629 if (instr->hydrogen()->object_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005630 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005631 Handle<Cell> cell = isolate()->factory()->NewCell(object);
danno@chromium.org41728482013-06-12 22:31:22 +00005632 __ cmp(reg, Operand::ForCell(cell));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005633 } else {
5634 Operand operand = ToOperand(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005635 __ cmp(operand, object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005636 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 DeoptimizeIf(not_equal, instr->environment());
5638}
5639
5640
danno@chromium.org59400602013-08-13 17:09:37 +00005641void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5642 {
5643 PushSafepointRegistersScope scope(this);
5644 __ push(object);
5645 __ xor_(esi, esi);
5646 __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance);
5647 RecordSafepointWithRegisters(
5648 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
5649
5650 __ test(eax, Immediate(kSmiTagMask));
5651 }
5652 DeoptimizeIf(zero, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005653}
5654
5655
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005656void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005657 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00005658 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005659 DeferredCheckMaps(LCodeGen* codegen,
5660 LCheckMaps* instr,
5661 Register object,
5662 const X87Stack& x87_stack)
5663 : LDeferredCode(codegen, x87_stack), instr_(instr), object_(object) {
danno@chromium.org59400602013-08-13 17:09:37 +00005664 SetExit(check_maps());
5665 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005666 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00005667 codegen()->DoDeferredInstanceMigration(instr_, object_);
5668 }
5669 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005670 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00005671 private:
5672 LCheckMaps* instr_;
5673 Label check_maps_;
5674 Register object_;
5675 };
5676
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005677 if (instr->hydrogen()->CanOmitMapChecks()) return;
danno@chromium.org59400602013-08-13 17:09:37 +00005678
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005679 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005680 ASSERT(input->IsRegister());
5681 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005682
danno@chromium.org59400602013-08-13 17:09:37 +00005683 DeferredCheckMaps* deferred = NULL;
5684 if (instr->hydrogen()->has_migration_target()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005685 deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_);
danno@chromium.org59400602013-08-13 17:09:37 +00005686 __ bind(deferred->check_maps());
5687 }
5688
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005689 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005690 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005691 for (int i = 0; i < map_set.size() - 1; i++) {
5692 Handle<Map> map = map_set.at(i).handle();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005693 __ CompareMap(reg, map, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005694 __ j(equal, &success);
5695 }
danno@chromium.org59400602013-08-13 17:09:37 +00005696
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005697 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
danno@chromium.org59400602013-08-13 17:09:37 +00005698 __ CompareMap(reg, map, &success);
5699 if (instr->hydrogen()->has_migration_target()) {
5700 __ j(not_equal, deferred->entry());
5701 } else {
5702 DeoptimizeIf(not_equal, instr->environment());
5703 }
5704
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005705 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005706}
5707
5708
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005709void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005710 CpuFeatureScope scope(masm(), SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005711 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005712 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005713 Register result_reg = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005714 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005715}
5716
5717
5718void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5719 ASSERT(instr->unclamped()->Equals(instr->result()));
5720 Register value_reg = ToRegister(instr->result());
5721 __ ClampUint8(value_reg);
5722}
5723
5724
5725void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005726 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005727
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005728 ASSERT(instr->unclamped()->Equals(instr->result()));
5729 Register input_reg = ToRegister(instr->unclamped());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005730 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005731 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005732 Label is_smi, done, heap_number;
5733
5734 __ JumpIfSmi(input_reg, &is_smi);
5735
5736 // Check for heap number
5737 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5738 factory()->heap_number_map());
5739 __ j(equal, &heap_number, Label::kNear);
5740
5741 // Check for undefined. Undefined is converted to zero for clamping
5742 // conversions.
5743 __ cmp(input_reg, factory()->undefined_value());
5744 DeoptimizeIf(not_equal, instr->environment());
5745 __ mov(input_reg, 0);
5746 __ jmp(&done, Label::kNear);
5747
5748 // Heap number
5749 __ bind(&heap_number);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005750 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005751 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005752 __ jmp(&done, Label::kNear);
5753
5754 // smi
5755 __ bind(&is_smi);
5756 __ SmiUntag(input_reg);
5757 __ ClampUint8(input_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005758 __ bind(&done);
5759}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005760
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005761
5762void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
5763 Register input_reg = ToRegister(instr->unclamped());
5764 Register result_reg = ToRegister(instr->result());
5765 Register scratch = ToRegister(instr->scratch());
5766 Register scratch2 = ToRegister(instr->scratch2());
5767 Register scratch3 = ToRegister(instr->scratch3());
5768 Label is_smi, done, heap_number, valid_exponent,
5769 largest_value, zero_result, maybe_nan_or_infinity;
5770
5771 __ JumpIfSmi(input_reg, &is_smi);
5772
5773 // Check for heap number
5774 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5775 factory()->heap_number_map());
5776 __ j(equal, &heap_number, Label::kFar);
5777
5778 // Check for undefined. Undefined is converted to zero for clamping
5779 // conversions.
5780 __ cmp(input_reg, factory()->undefined_value());
5781 DeoptimizeIf(not_equal, instr->environment());
5782 __ jmp(&zero_result);
5783
5784 // Heap number
5785 __ bind(&heap_number);
5786
5787 // Surprisingly, all of the hand-crafted bit-manipulations below are much
5788 // faster than the x86 FPU built-in instruction, especially since "banker's
5789 // rounding" would be additionally very expensive
5790
5791 // Get exponent word.
5792 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5793 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5794
5795 // Test for negative values --> clamp to zero
5796 __ test(scratch, scratch);
5797 __ j(negative, &zero_result);
5798
5799 // Get exponent alone in scratch2.
5800 __ mov(scratch2, scratch);
5801 __ and_(scratch2, HeapNumber::kExponentMask);
5802 __ shr(scratch2, HeapNumber::kExponentShift);
5803 __ j(zero, &zero_result);
5804 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
5805 __ j(negative, &zero_result);
5806
5807 const uint32_t non_int8_exponent = 7;
5808 __ cmp(scratch2, Immediate(non_int8_exponent + 1));
5809 // If the exponent is too big, check for special values.
5810 __ j(greater, &maybe_nan_or_infinity, Label::kNear);
5811
5812 __ bind(&valid_exponent);
5813 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5814 // < 7. The shift bias is the number of bits to shift the mantissa such that
5815 // with an exponent of 7 such the that top-most one is in bit 30, allowing
5816 // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
5817 // 1).
5818 int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
5819 __ lea(result_reg, MemOperand(scratch2, shift_bias));
5820 // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the
5821 // top bits of the mantissa.
5822 __ and_(scratch, HeapNumber::kMantissaMask);
5823 // Put back the implicit 1 of the mantissa
5824 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5825 // Shift up to round
5826 __ shl_cl(scratch);
5827 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
5828 // use the bit in the "ones" place and add it to the "halves" place, which has
5829 // the effect of rounding to even.
5830 __ mov(scratch2, scratch);
5831 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
5832 const uint32_t one_bit_shift = one_half_bit_shift + 1;
5833 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
5834 __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
5835 Label no_round;
5836 __ j(less, &no_round);
5837 Label round_up;
5838 __ mov(scratch2, Immediate(1 << one_half_bit_shift));
5839 __ j(greater, &round_up);
5840 __ test(scratch3, scratch3);
5841 __ j(not_zero, &round_up);
5842 __ mov(scratch2, scratch);
5843 __ and_(scratch2, Immediate(1 << one_bit_shift));
5844 __ shr(scratch2, 1);
5845 __ bind(&round_up);
5846 __ add(scratch, scratch2);
5847 __ j(overflow, &largest_value);
5848 __ bind(&no_round);
5849 __ shr(scratch, 23);
5850 __ mov(result_reg, scratch);
5851 __ jmp(&done, Label::kNear);
5852
5853 __ bind(&maybe_nan_or_infinity);
5854 // Check for NaN/Infinity, all other values map to 255
5855 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
5856 __ j(not_equal, &largest_value, Label::kNear);
5857
5858 // Check for NaN, which differs from Infinity in that at least one mantissa
5859 // bit is set.
5860 __ and_(scratch, HeapNumber::kMantissaMask);
5861 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5862 __ j(not_zero, &zero_result); // M!=0 --> NaN
5863 // Infinity -> Fall through to map to 255.
5864
5865 __ bind(&largest_value);
5866 __ mov(result_reg, Immediate(255));
5867 __ jmp(&done, Label::kNear);
5868
5869 __ bind(&zero_result);
5870 __ xor_(result_reg, result_reg);
5871 __ jmp(&done);
5872
5873 // smi
5874 __ bind(&is_smi);
5875 if (!input_reg.is(result_reg)) {
5876 __ mov(result_reg, input_reg);
5877 }
5878 __ SmiUntag(result_reg);
5879 __ ClampUint8(result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005880 __ bind(&done);
5881}
5882
5883
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005884void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005885 class DeferredAllocate V8_FINAL : public LDeferredCode {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005886 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005887 DeferredAllocate(LCodeGen* codegen,
5888 LAllocate* instr,
5889 const X87Stack& x87_stack)
5890 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005891 virtual void Generate() V8_OVERRIDE {
5892 codegen()->DoDeferredAllocate(instr_);
5893 }
5894 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005895 private:
5896 LAllocate* instr_;
5897 };
5898
5899 DeferredAllocate* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005900 new(zone()) DeferredAllocate(this, instr, x87_stack_);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005901
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005902 Register result = ToRegister(instr->result());
5903 Register temp = ToRegister(instr->temp());
5904
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005905 // Allocate memory for the object.
5906 AllocationFlags flags = TAG_OBJECT;
5907 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5908 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5909 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005910 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5911 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5912 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005913 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005914 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5915 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005916 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005917 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005918
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005919 if (instr->size()->IsConstantOperand()) {
5920 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005921 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005922 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005923 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005924 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005925 }
5926
5927 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005928
5929 if (instr->hydrogen()->MustPrefillWithFiller()) {
5930 if (instr->size()->IsConstantOperand()) {
5931 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5932 __ mov(temp, (size / kPointerSize) - 1);
5933 } else {
5934 temp = ToRegister(instr->size());
5935 __ shr(temp, kPointerSizeLog2);
5936 __ dec(temp);
5937 }
5938 Label loop;
5939 __ bind(&loop);
5940 __ mov(FieldOperand(result, temp, times_pointer_size, 0),
5941 isolate()->factory()->one_pointer_filler_map());
5942 __ dec(temp);
5943 __ j(not_zero, &loop);
5944 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005945}
5946
5947
5948void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005949 Register result = ToRegister(instr->result());
5950
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005951 // TODO(3095996): Get rid of this. For now, we need to make the
5952 // result register contain a valid pointer because it is already
5953 // contained in the register pointer map.
danno@chromium.orgf005df62013-04-30 16:36:45 +00005954 __ mov(result, Immediate(Smi::FromInt(0)));
5955
5956 PushSafepointRegistersScope scope(this);
5957 if (instr->size()->IsRegister()) {
5958 Register size = ToRegister(instr->size());
5959 ASSERT(!size.is(result));
5960 __ SmiTag(ToRegister(instr->size()));
5961 __ push(size);
5962 } else {
5963 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5964 __ push(Immediate(Smi::FromInt(size)));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005965 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00005966
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005967 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5968 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5969 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005970 CallRuntimeFromDeferred(
5971 Runtime::kAllocateInOldPointerSpace, 1, instr, instr->context());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005972 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5973 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005974 CallRuntimeFromDeferred(
5975 Runtime::kAllocateInOldDataSpace, 1, instr, instr->context());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005976 } else {
5977 CallRuntimeFromDeferred(
5978 Runtime::kAllocateInNewSpace, 1, instr, instr->context());
5979 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005980 __ StoreToSafepointRegisterSlot(result, eax);
5981}
5982
5983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005984void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005985 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005986 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005987 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005988}
5989
5990
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005991void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005992 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005993 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005994 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005995 // ecx = literals array.
5996 // ebx = regexp literal.
5997 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005998 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005999 int literal_offset =
6000 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
6001 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006002 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006003 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006004 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006005
6006 // Create regexp literal using runtime function
6007 // Result will be in eax.
6008 __ push(ecx);
6009 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
6010 __ push(Immediate(instr->hydrogen()->pattern()));
6011 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006012 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006013 __ mov(ebx, eax);
6014
6015 __ bind(&materialized);
6016 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
6017 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00006018 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006019 __ jmp(&allocated);
6020
6021 __ bind(&runtime_allocate);
6022 __ push(ebx);
6023 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006024 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006025 __ pop(ebx);
6026
6027 __ bind(&allocated);
6028 // Copy the content into the newly allocated memory.
6029 // (Unroll copy loop once for better throughput).
6030 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
6031 __ mov(edx, FieldOperand(ebx, i));
6032 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
6033 __ mov(FieldOperand(eax, i), edx);
6034 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
6035 }
6036 if ((size % (2 * kPointerSize)) != 0) {
6037 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
6038 __ mov(FieldOperand(eax, size - kPointerSize), edx);
6039 }
6040}
6041
6042
6043void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006044 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006045 // Use the fast case closure allocation code that allocates in new
6046 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006047 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006048 if (!pretenure && instr->hydrogen()->has_no_literals()) {
6049 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
6050 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00006051 __ mov(ebx, Immediate(instr->hydrogen()->shared_info()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006052 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006053 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006054 __ push(esi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006055 __ push(Immediate(instr->hydrogen()->shared_info()));
6056 __ push(Immediate(pretenure ? factory()->true_value()
6057 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006058 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006059 }
6060}
6061
6062
6063void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006064 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006065 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006066 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006067}
6068
6069
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006070void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006071 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006072
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006073 Condition final_branch_condition =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006074 EmitTypeofIs(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
6075 input, instr->type_literal());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006076 if (final_branch_condition != no_condition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006077 EmitBranch(instr, final_branch_condition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006078 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006079}
6080
6081
6082Condition LCodeGen::EmitTypeofIs(Label* true_label,
6083 Label* false_label,
6084 Register input,
6085 Handle<String> type_name) {
6086 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006087 if (type_name->Equals(heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006088 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006089 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006090 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006091 final_branch_condition = equal;
6092
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006093 } else if (type_name->Equals(heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006094 __ JumpIfSmi(input, false_label);
6095 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
6096 __ j(above_equal, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006097 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6098 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006099 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006100
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006101 } else if (type_name->Equals(heap()->symbol_string())) {
6102 __ JumpIfSmi(input, false_label);
6103 __ CmpObjectType(input, SYMBOL_TYPE, input);
6104 final_branch_condition = equal;
6105
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006106 } else if (type_name->Equals(heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006107 __ cmp(input, factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006108 __ j(equal, true_label);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006110 final_branch_condition = equal;
6111
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006112 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006113 __ cmp(input, factory()->null_value());
6114 final_branch_condition = equal;
6115
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006116 } else if (type_name->Equals(heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 __ cmp(input, factory()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006118 __ j(equal, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006119 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006120 // Check for undetectable objects => true.
6121 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
6122 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6123 1 << Map::kIsUndetectable);
6124 final_branch_condition = not_zero;
6125
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006126 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006127 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006128 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006129 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
6130 __ j(equal, true_label);
6131 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
6132 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006133
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006134 } else if (type_name->Equals(heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006135 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006136 if (!FLAG_harmony_typeof) {
6137 __ cmp(input, factory()->null_value());
6138 __ j(equal, true_label);
6139 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006140 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006141 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006142 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
6143 __ j(above, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006144 // Check for undetectable objects => false.
6145 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6146 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006147 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006148
6149 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006150 __ jmp(false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006151 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006152 return final_branch_condition;
6153}
6154
6155
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006156void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006157 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006158
6159 EmitIsConstructCall(temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006160 EmitBranch(instr, equal);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006161}
6162
6163
6164void LCodeGen::EmitIsConstructCall(Register temp) {
6165 // Get the frame pointer for the calling frame.
6166 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6167
6168 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006169 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006170 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
6171 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006172 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006173 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
6174
6175 // Check the marker in the calling frame.
6176 __ bind(&check_frame_marker);
6177 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
6178 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
6179}
6180
6181
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006182void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006183 if (!info()->IsStub()) {
6184 // Ensure that we have enough space after the previous lazy-bailout
6185 // instruction for patching the code here.
6186 int current_pc = masm()->pc_offset();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006187 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
6188 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006189 __ Nop(padding_size);
6190 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006191 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006192 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006193}
6194
6195
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006196void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006197 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006198 ASSERT(instr->HasEnvironment());
6199 LEnvironment* env = instr->environment();
6200 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6201 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006202}
6203
6204
6205void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00006206 Deoptimizer::BailoutType type = instr->hydrogen()->type();
6207 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
6208 // needed return address), even though the implementation of LAZY and EAGER is
6209 // now identical. When LAZY is eventually completely folded into EAGER, remove
6210 // the special case below.
6211 if (info()->IsStub() && type == Deoptimizer::EAGER) {
6212 type = Deoptimizer::LAZY;
danno@chromium.orgaefd6072013-05-14 14:11:47 +00006213 }
danno@chromium.org59400602013-08-13 17:09:37 +00006214 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00006215 DeoptimizeIf(no_condition, instr->environment(), type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006216}
6217
6218
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006219void LCodeGen::DoDummyUse(LDummyUse* instr) {
6220 // Nothing to see here, move on!
6221}
6222
6223
ager@chromium.org04921a82011-06-27 13:21:41 +00006224void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006225 PushSafepointRegistersScope scope(this);
6226 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6227 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6228 RecordSafepointWithLazyDeopt(
6229 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6230 ASSERT(instr->HasEnvironment());
6231 LEnvironment* env = instr->environment();
6232 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006233}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006234
ager@chromium.org04921a82011-06-27 13:21:41 +00006235
6236void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00006237 class DeferredStackCheck V8_FINAL : public LDeferredCode {
ager@chromium.org04921a82011-06-27 13:21:41 +00006238 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006239 DeferredStackCheck(LCodeGen* codegen,
6240 LStackCheck* instr,
6241 const X87Stack& x87_stack)
6242 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00006243 virtual void Generate() V8_OVERRIDE {
6244 codegen()->DoDeferredStackCheck(instr_);
6245 }
6246 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006247 private:
6248 LStackCheck* instr_;
6249 };
6250
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006251 ASSERT(instr->HasEnvironment());
6252 LEnvironment* env = instr->environment();
6253 // There is no LLazyBailout instruction for stack-checks. We have to
6254 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006255 if (instr->hydrogen()->is_function_entry()) {
6256 // Perform stack overflow check.
6257 Label done;
6258 ExternalReference stack_limit =
6259 ExternalReference::address_of_stack_limit(isolate());
6260 __ cmp(esp, Operand::StaticVariable(stack_limit));
6261 __ j(above_equal, &done, Label::kNear);
6262
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006263 ASSERT(instr->context()->IsRegister());
6264 ASSERT(ToRegister(instr->context()).is(esi));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00006265 CallCode(isolate()->builtins()->StackCheck(),
6266 RelocInfo::CODE_TARGET,
6267 instr);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006268 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00006269 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006270 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6271 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006272 } else {
6273 ASSERT(instr->hydrogen()->is_backwards_branch());
6274 // Perform stack overflow check if this goto needs it before jumping.
6275 DeferredStackCheck* deferred_stack_check =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006276 new(zone()) DeferredStackCheck(this, instr, x87_stack_);
ager@chromium.org04921a82011-06-27 13:21:41 +00006277 ExternalReference stack_limit =
6278 ExternalReference::address_of_stack_limit(isolate());
6279 __ cmp(esp, Operand::StaticVariable(stack_limit));
6280 __ j(below, deferred_stack_check->entry());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006281 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00006282 __ bind(instr->done_label());
6283 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006284 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6285 // Don't record a deoptimization index for the safepoint here.
6286 // This will be done explicitly when emitting call and the safepoint in
6287 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006288 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006289}
6290
6291
6292void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6293 // This is a pseudo-instruction that ensures that the environment here is
6294 // properly registered for deoptimization and records the assembler's PC
6295 // offset.
6296 LEnvironment* environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006297
6298 // If the environment were already registered, we would have no way of
6299 // backpatching it with the spill slot operands.
6300 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006301 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006302
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006303 GenerateOsrPrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006304}
6305
6306
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006307void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
6308 __ cmp(eax, isolate()->factory()->undefined_value());
6309 DeoptimizeIf(equal, instr->environment());
6310
6311 __ cmp(eax, isolate()->factory()->null_value());
6312 DeoptimizeIf(equal, instr->environment());
6313
6314 __ test(eax, Immediate(kSmiTagMask));
6315 DeoptimizeIf(zero, instr->environment());
6316
6317 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6318 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6319 DeoptimizeIf(below_equal, instr->environment());
6320
6321 Label use_cache, call_runtime;
6322 __ CheckEnumCache(&call_runtime);
6323
6324 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6325 __ jmp(&use_cache, Label::kNear);
6326
6327 // Get the set of properties to enumerate.
6328 __ bind(&call_runtime);
6329 __ push(eax);
6330 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6331
6332 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6333 isolate()->factory()->meta_map());
6334 DeoptimizeIf(not_equal, instr->environment());
6335 __ bind(&use_cache);
6336}
6337
6338
6339void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6340 Register map = ToRegister(instr->map());
6341 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006342 Label load_cache, done;
6343 __ EnumLength(result, map);
6344 __ cmp(result, Immediate(Smi::FromInt(0)));
6345 __ j(not_equal, &load_cache);
6346 __ mov(result, isolate()->factory()->empty_fixed_array());
6347 __ jmp(&done);
6348
6349 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006350 __ LoadInstanceDescriptors(map, result);
6351 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006352 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006353 __ mov(result,
6354 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006355 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006356 __ test(result, result);
6357 DeoptimizeIf(equal, instr->environment());
6358}
6359
6360
6361void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6362 Register object = ToRegister(instr->value());
6363 __ cmp(ToRegister(instr->map()),
6364 FieldOperand(object, HeapObject::kMapOffset));
6365 DeoptimizeIf(not_equal, instr->environment());
6366}
6367
6368
6369void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6370 Register object = ToRegister(instr->object());
6371 Register index = ToRegister(instr->index());
6372
6373 Label out_of_object, done;
6374 __ cmp(index, Immediate(0));
6375 __ j(less, &out_of_object);
6376 __ mov(object, FieldOperand(object,
6377 index,
6378 times_half_pointer_size,
6379 JSObject::kHeaderSize));
6380 __ jmp(&done, Label::kNear);
6381
6382 __ bind(&out_of_object);
6383 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6384 __ neg(index);
6385 // Index is now equal to out of object property index plus 1.
6386 __ mov(object, FieldOperand(object,
6387 index,
6388 times_half_pointer_size,
6389 FixedArray::kHeaderSize - kPointerSize));
6390 __ bind(&done);
6391}
6392
6393
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006394#undef __
6395
6396} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006397
6398#endif // V8_TARGET_ARCH_IA32