blob: 1a20fc3b6815c1d2c69a0dfdfb2a209e1f2098e4 [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());
machenbach@chromium.orgddf38112013-12-04 09:42:52 +0000106 RegisterDependentCodeForEmbeddedMaps(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000107 PopulateDeoptimizationData(code);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000108 if (!info()->IsStub()) {
109 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
110 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000111 info()->CommitDependencies(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000112}
113
114
danno@chromium.org59400602013-08-13 17:09:37 +0000115void LCodeGen::Abort(BailoutReason reason) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000116 info()->set_bailout_reason(reason);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000117 status_ = ABORTED;
118}
119
120
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000121#ifdef _MSC_VER
122void LCodeGen::MakeSureStackPagesMapped(int offset) {
123 const int kPageSize = 4 * KB;
124 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
125 __ mov(Operand(esp, offset), eax);
126 }
127}
128#endif
129
130
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000131void LCodeGen::SaveCallerDoubles() {
132 ASSERT(info()->saves_caller_doubles());
133 ASSERT(NeedsEagerFrame());
134 Comment(";;; Save clobbered callee double registers");
135 CpuFeatureScope scope(masm(), SSE2);
136 int count = 0;
137 BitVector* doubles = chunk()->allocated_double_registers();
138 BitVector::Iterator save_iterator(doubles);
139 while (!save_iterator.Done()) {
140 __ movsd(MemOperand(esp, count * kDoubleSize),
141 XMMRegister::FromAllocationIndex(save_iterator.Current()));
142 save_iterator.Advance();
143 count++;
144 }
145}
146
147
148void LCodeGen::RestoreCallerDoubles() {
149 ASSERT(info()->saves_caller_doubles());
150 ASSERT(NeedsEagerFrame());
151 Comment(";;; Restore clobbered callee double registers");
152 CpuFeatureScope scope(masm(), SSE2);
153 BitVector* doubles = chunk()->allocated_double_registers();
154 BitVector::Iterator save_iterator(doubles);
155 int count = 0;
156 while (!save_iterator.Done()) {
157 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
158 MemOperand(esp, count * kDoubleSize));
159 save_iterator.Advance();
160 count++;
161 }
162}
163
164
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000165bool LCodeGen::GeneratePrologue() {
166 ASSERT(is_generating());
167
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000168 if (info()->IsOptimizing()) {
169 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000170
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000171#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000172 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000173 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000174 __ int3();
175 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000176#endif
177
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000178 // Strict mode functions and builtins need to replace the receiver
179 // with undefined when called as functions (without an explicit
180 // receiver object). ecx is zero for method calls and non-zero for
181 // function calls.
182 if (!info_->is_classic_mode() || info_->is_native()) {
183 Label ok;
184 __ test(ecx, Operand(ecx));
185 __ j(zero, &ok, Label::kNear);
186 // +1 for return address.
187 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize;
188 __ mov(Operand(esp, receiver_offset),
189 Immediate(isolate()->factory()->undefined_value()));
190 __ bind(&ok);
191 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000192
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000193 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000194 // Move state of dynamic frame alignment into edx.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +0000195 __ Set(edx, Immediate(kNoAlignmentPadding));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000196
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000197 Label do_not_pad, align_loop;
198 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize);
199 // Align esp + 4 to a multiple of 2 * kPointerSize.
200 __ test(esp, Immediate(kPointerSize));
201 __ j(not_zero, &do_not_pad, Label::kNear);
202 __ push(Immediate(0));
203 __ mov(ebx, esp);
204 __ mov(edx, Immediate(kAlignmentPaddingPushed));
205 // Copy arguments, receiver, and return address.
206 __ mov(ecx, Immediate(scope()->num_parameters() + 2));
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000207
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000208 __ bind(&align_loop);
209 __ mov(eax, Operand(ebx, 1 * kPointerSize));
210 __ mov(Operand(ebx, 0), eax);
211 __ add(Operand(ebx), Immediate(kPointerSize));
212 __ dec(ecx);
213 __ j(not_zero, &align_loop, Label::kNear);
214 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
215 __ bind(&do_not_pad);
216 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000217 }
218
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000219 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000220 if (NeedsEagerFrame()) {
221 ASSERT(!frame_is_built_);
222 frame_is_built_ = true;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000223 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000224 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000225 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000226
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000227 if (info()->IsOptimizing() &&
228 dynamic_frame_alignment_ &&
229 FLAG_debug_code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000230 __ test(esp, Immediate(kPointerSize));
danno@chromium.org59400602013-08-13 17:09:37 +0000231 __ Assert(zero, kFrameIsExpectedToBeAligned);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000232 }
233
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000234 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000235 int slots = GetStackSlotCount();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000236 ASSERT(slots != 0 || !info()->IsOptimizing());
237 if (slots > 0) {
238 if (slots == 1) {
239 if (dynamic_frame_alignment_) {
240 __ push(edx);
241 } else {
242 __ push(Immediate(kNoAlignmentPadding));
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +0000243 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000244 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000245 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000246 __ sub(Operand(esp), Immediate(slots * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000247#ifdef _MSC_VER
248 MakeSureStackPagesMapped(slots * kPointerSize);
249#endif
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000250 __ push(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000251 __ mov(Operand(eax), Immediate(slots));
252 Label loop;
253 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000254 __ mov(MemOperand(esp, eax, times_4, 0),
255 Immediate(kSlotsZapValue));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000256 __ dec(eax);
257 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000258 __ pop(eax);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000259 } else {
260 __ sub(Operand(esp), Immediate(slots * kPointerSize));
261#ifdef _MSC_VER
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000262 MakeSureStackPagesMapped(slots * kPointerSize);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000263#endif
264 }
265
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000266 if (support_aligned_spilled_doubles_) {
267 Comment(";;; Store dynamic frame alignment tag for spilled doubles");
268 // Store dynamic frame alignment state in the first local.
269 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset;
270 if (dynamic_frame_alignment_) {
271 __ mov(Operand(ebp, offset), edx);
272 } else {
273 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding));
274 }
275 }
276 }
277
278 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000279 SaveCallerDoubles();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000280 }
281 }
282
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000283 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000284 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000285 if (heap_slots > 0) {
286 Comment(";;; Allocate local context");
287 // Argument to NewContext is the function, which is still in edi.
288 __ push(edi);
289 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
290 FastNewContextStub stub(heap_slots);
291 __ CallStub(&stub);
292 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000293 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000294 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000295 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000296 // Context is returned in both eax and esi. It replaces the context
297 // passed to us. It's saved in the stack and kept live in esi.
298 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
299
300 // Copy parameters into context if necessary.
301 int num_parameters = scope()->num_parameters();
302 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000303 Variable* var = scope()->parameter(i);
304 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000305 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
306 (num_parameters - 1 - i) * kPointerSize;
307 // Load parameter from stack.
308 __ mov(eax, Operand(ebp, parameter_offset));
309 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000310 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000311 __ mov(Operand(esi, context_offset), eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000312 // Update the write barrier. This clobbers eax and ebx.
313 __ RecordWriteContextSlot(esi,
314 context_offset,
315 eax,
316 ebx,
317 kDontSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000318 }
319 }
320 Comment(";;; End allocate local context");
321 }
322
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000323 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000324 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000325 // We have not executed any compiled code yet, so esi still holds the
326 // incoming context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000327 __ CallRuntime(Runtime::kTraceEnter, 0);
328 }
329 return !is_aborted();
330}
331
332
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000333void LCodeGen::GenerateOsrPrologue() {
334 // Generate the OSR entry prologue at the first unknown OSR value, or if there
335 // are none, at the OSR entrypoint instruction.
336 if (osr_pc_offset_ >= 0) return;
337
338 osr_pc_offset_ = masm()->pc_offset();
339
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000340 // Move state of dynamic frame alignment into edx.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +0000341 __ Set(edx, Immediate(kNoAlignmentPadding));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000342
343 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) {
344 Label do_not_pad, align_loop;
345 // Align ebp + 4 to a multiple of 2 * kPointerSize.
346 __ test(ebp, Immediate(kPointerSize));
347 __ j(zero, &do_not_pad, Label::kNear);
348 __ push(Immediate(0));
349 __ mov(ebx, esp);
350 __ mov(edx, Immediate(kAlignmentPaddingPushed));
351
352 // Move all parts of the frame over one word. The frame consists of:
353 // unoptimized frame slots, alignment state, context, frame pointer, return
354 // address, receiver, and the arguments.
355 __ mov(ecx, Immediate(scope()->num_parameters() +
356 5 + graph()->osr()->UnoptimizedFrameSlots()));
357
358 __ bind(&align_loop);
359 __ mov(eax, Operand(ebx, 1 * kPointerSize));
360 __ mov(Operand(ebx, 0), eax);
361 __ add(Operand(ebx), Immediate(kPointerSize));
362 __ dec(ecx);
363 __ j(not_zero, &align_loop, Label::kNear);
364 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
365 __ sub(Operand(ebp), Immediate(kPointerSize));
366 __ bind(&do_not_pad);
367 }
368
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000369 // Save the first local, which is overwritten by the alignment state.
370 Operand alignment_loc = MemOperand(ebp, -3 * kPointerSize);
371 __ push(alignment_loc);
372
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000373 // Set the dynamic frame alignment state.
374 __ mov(alignment_loc, edx);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000375
376 // Adjust the frame size, subsuming the unoptimized frame into the
377 // optimized frame.
378 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
379 ASSERT(slots >= 1);
380 __ sub(esp, Immediate((slots - 1) * kPointerSize));
381}
382
383
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000384void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
385 if (!CpuFeatures::IsSupported(SSE2)) FlushX87StackIfNecessary(instr);
386}
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000387
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000388
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000389void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
390 if (!CpuFeatures::IsSupported(SSE2)) {
391 if (instr->IsGoto()) {
392 x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr));
393 } else if (FLAG_debug_code && FLAG_enable_slow_asserts &&
394 !instr->IsGap() && !instr->IsReturn()) {
395 if (instr->ClobbersDoubleRegisters()) {
396 if (instr->HasDoubleRegisterResult()) {
397 ASSERT_EQ(1, x87_stack_.depth());
398 } else {
399 ASSERT_EQ(0, x87_stack_.depth());
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000400 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000401 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000402 __ VerifyX87StackDepth(x87_stack_.depth());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000403 }
404 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000405}
406
407
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000408bool LCodeGen::GenerateJumpTable() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000409 Label needs_frame;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000410 if (jump_table_.length() > 0) {
411 Comment(";;; -------------------- Jump table --------------------");
412 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000413 for (int i = 0; i < jump_table_.length(); i++) {
414 __ bind(&jump_table_[i].label);
415 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000416 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000417 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000418 if (id == Deoptimizer::kNotDeoptimizationEntry) {
419 Comment(";;; jump table entry %d.", i);
420 } else {
421 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
422 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000423 if (jump_table_[i].needs_frame) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000424 ASSERT(!info()->saves_caller_doubles());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000425 __ push(Immediate(ExternalReference::ForDeoptEntry(entry)));
danno@chromium.org169691d2013-07-15 08:01:13 +0000426 if (needs_frame.is_bound()) {
427 __ jmp(&needs_frame);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000428 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000429 __ bind(&needs_frame);
430 __ push(MemOperand(ebp, StandardFrameConstants::kContextOffset));
431 // This variant of deopt can only be used with stubs. Since we don't
432 // have a function pointer to install in the stack frame that we're
433 // building, install a special marker there instead.
434 ASSERT(info()->IsStub());
435 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
436 // Push a PC inside the function so that the deopt code can find where
437 // the deopt comes from. It doesn't have to be the precise return
438 // address of a "calling" LAZY deopt, it only has to be somewhere
439 // inside the code body.
440 Label push_approx_pc;
441 __ call(&push_approx_pc);
442 __ bind(&push_approx_pc);
443 // Push the continuation which was stashed were the ebp should
444 // be. Replace it with the saved ebp.
445 __ push(MemOperand(esp, 3 * kPointerSize));
446 __ mov(MemOperand(esp, 4 * kPointerSize), ebp);
447 __ lea(ebp, MemOperand(esp, 4 * kPointerSize));
448 __ ret(0); // Call the continuation without clobbering registers.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000449 }
450 } else {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000451 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
452 RestoreCallerDoubles();
453 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000454 __ call(entry, RelocInfo::RUNTIME_ENTRY);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000455 }
456 }
457 return !is_aborted();
458}
459
460
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000461bool LCodeGen::GenerateDeferredCode() {
462 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000463 if (deferred_.length() > 0) {
464 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
465 LDeferredCode* code = deferred_[i];
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000466 X87Stack copy(code->x87_stack());
467 x87_stack_ = copy;
danno@chromium.org59400602013-08-13 17:09:37 +0000468
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000469 HValue* value =
470 instructions_->at(code->instruction_index())->hydrogen_value();
471 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000472
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000473 Comment(";;; <@%d,#%d> "
474 "-------------------- Deferred %s --------------------",
475 code->instruction_index(),
476 code->instr()->hydrogen_value()->id(),
477 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000478 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000479 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000480 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000481 ASSERT(!frame_is_built_);
482 ASSERT(info()->IsStub());
483 frame_is_built_ = true;
484 // Build the frame in such a way that esi isn't trashed.
485 __ push(ebp); // Caller's frame pointer.
486 __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
487 __ push(Immediate(Smi::FromInt(StackFrame::STUB)));
488 __ lea(ebp, Operand(esp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000489 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000490 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000491 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000492 if (NeedsDeferredFrame()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000493 __ bind(code->done());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000494 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000495 ASSERT(frame_is_built_);
496 frame_is_built_ = false;
497 __ mov(esp, ebp);
498 __ pop(ebp);
499 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000500 __ jmp(code->exit());
501 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000502 }
503
504 // Deferred code is the last part of the instruction sequence. Mark
505 // the generated code as done unless we bailed out.
506 if (!is_aborted()) status_ = DONE;
507 return !is_aborted();
508}
509
510
511bool LCodeGen::GenerateSafepointTable() {
512 ASSERT(is_done());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000513 if (!info()->IsStub()) {
514 // For lazy deoptimization we need space to patch a call after every call.
515 // Ensure there is always space for such patching, even if the code ends
516 // in a call.
517 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
518 while (masm()->pc_offset() < target_offset) {
519 masm()->nop();
520 }
521 }
danno@chromium.org160a7b02011-04-18 15:51:38 +0000522 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000523 return !is_aborted();
524}
525
526
527Register LCodeGen::ToRegister(int index) const {
528 return Register::FromAllocationIndex(index);
529}
530
531
danno@chromium.org169691d2013-07-15 08:01:13 +0000532X87Register LCodeGen::ToX87Register(int index) const {
533 return X87Register::FromAllocationIndex(index);
534}
535
536
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000537XMMRegister LCodeGen::ToDoubleRegister(int index) const {
538 return XMMRegister::FromAllocationIndex(index);
539}
540
541
danno@chromium.org169691d2013-07-15 08:01:13 +0000542void LCodeGen::X87LoadForUsage(X87Register reg) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000543 ASSERT(x87_stack_.Contains(reg));
544 x87_stack_.Fxch(reg);
545 x87_stack_.pop();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000546}
547
548
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000549void LCodeGen::X87LoadForUsage(X87Register reg1, X87Register reg2) {
550 ASSERT(x87_stack_.Contains(reg1));
551 ASSERT(x87_stack_.Contains(reg2));
552 x87_stack_.Fxch(reg1, 1);
553 x87_stack_.Fxch(reg2);
554 x87_stack_.pop();
555 x87_stack_.pop();
556}
557
558
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000559void LCodeGen::X87Stack::Fxch(X87Register reg, int other_slot) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000560 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000561 ASSERT(Contains(reg) && stack_depth_ > other_slot);
562 int i = ArrayIndex(reg);
563 int st = st2idx(i);
danno@chromium.org169691d2013-07-15 08:01:13 +0000564 if (st != other_slot) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000565 int other_i = st2idx(other_slot);
566 X87Register other = stack_[other_i];
567 stack_[other_i] = reg;
568 stack_[i] = other;
danno@chromium.org169691d2013-07-15 08:01:13 +0000569 if (st == 0) {
570 __ fxch(other_slot);
571 } else if (other_slot == 0) {
572 __ fxch(st);
573 } else {
574 __ fxch(st);
575 __ fxch(other_slot);
576 __ fxch(st);
577 }
578 }
579}
580
581
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000582int LCodeGen::X87Stack::st2idx(int pos) {
583 return stack_depth_ - pos - 1;
danno@chromium.org169691d2013-07-15 08:01:13 +0000584}
585
586
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000587int LCodeGen::X87Stack::ArrayIndex(X87Register reg) {
588 for (int i = 0; i < stack_depth_; i++) {
589 if (stack_[i].is(reg)) return i;
danno@chromium.org169691d2013-07-15 08:01:13 +0000590 }
591 UNREACHABLE();
592 return -1;
593}
594
595
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000596bool LCodeGen::X87Stack::Contains(X87Register reg) {
597 for (int i = 0; i < stack_depth_; i++) {
598 if (stack_[i].is(reg)) return true;
danno@chromium.org169691d2013-07-15 08:01:13 +0000599 }
600 return false;
601}
602
603
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000604void LCodeGen::X87Stack::Free(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000605 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000606 ASSERT(Contains(reg));
607 int i = ArrayIndex(reg);
608 int st = st2idx(i);
danno@chromium.org169691d2013-07-15 08:01:13 +0000609 if (st > 0) {
610 // keep track of how fstp(i) changes the order of elements
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000611 int tos_i = st2idx(0);
612 stack_[i] = stack_[tos_i];
danno@chromium.org169691d2013-07-15 08:01:13 +0000613 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000614 pop();
danno@chromium.org169691d2013-07-15 08:01:13 +0000615 __ fstp(st);
616}
617
618
619void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000620 if (x87_stack_.Contains(dst)) {
621 x87_stack_.Fxch(dst);
danno@chromium.org169691d2013-07-15 08:01:13 +0000622 __ fstp(0);
623 } else {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000624 x87_stack_.push(dst);
danno@chromium.org169691d2013-07-15 08:01:13 +0000625 }
626 X87Fld(src, opts);
627}
628
629
630void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000631 ASSERT(!src.is_reg_only());
632 switch (opts) {
633 case kX87DoubleOperand:
634 __ fld_d(src);
635 break;
636 case kX87FloatOperand:
637 __ fld_s(src);
638 break;
639 case kX87IntOperand:
640 __ fild_s(src);
641 break;
642 default:
643 UNREACHABLE();
danno@chromium.org169691d2013-07-15 08:01:13 +0000644 }
645}
646
647
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000648void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) {
649 ASSERT(!dst.is_reg_only());
650 x87_stack_.Fxch(src);
651 switch (opts) {
652 case kX87DoubleOperand:
653 __ fst_d(dst);
654 break;
655 case kX87IntOperand:
656 __ fist_s(dst);
657 break;
658 default:
659 UNREACHABLE();
660 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000661}
662
663
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000664void LCodeGen::X87Stack::PrepareToWrite(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000665 ASSERT(is_mutable_);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000666 if (Contains(reg)) {
667 Free(reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000668 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000669 // Mark this register as the next register to write to
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000670 stack_[stack_depth_] = reg;
danno@chromium.org169691d2013-07-15 08:01:13 +0000671}
672
673
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000674void LCodeGen::X87Stack::CommitWrite(X87Register reg) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000675 ASSERT(is_mutable_);
danno@chromium.org169691d2013-07-15 08:01:13 +0000676 // Assert the reg is prepared to write, but not on the virtual stack yet
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000677 ASSERT(!Contains(reg) && stack_[stack_depth_].is(reg) &&
678 stack_depth_ < X87Register::kNumAllocatableRegisters);
679 stack_depth_++;
danno@chromium.org169691d2013-07-15 08:01:13 +0000680}
681
682
683void LCodeGen::X87PrepareBinaryOp(
684 X87Register left, X87Register right, X87Register result) {
685 // You need to use DefineSameAsFirst for x87 instructions
686 ASSERT(result.is(left));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000687 x87_stack_.Fxch(right, 1);
688 x87_stack_.Fxch(left);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000689}
690
691
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000692void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) {
693 if (stack_depth_ > 0 && instr->ClobbersDoubleRegisters()) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000694 bool double_inputs = instr->HasDoubleRegisterInput();
695
696 // Flush stack from tos down, since FreeX87() will mess with tos
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000697 for (int i = stack_depth_-1; i >= 0; i--) {
698 X87Register reg = stack_[i];
danno@chromium.org169691d2013-07-15 08:01:13 +0000699 // Skip registers which contain the inputs for the next instruction
700 // when flushing the stack
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000701 if (double_inputs && instr->IsDoubleInput(reg, cgen)) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000702 continue;
703 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000704 Free(reg);
705 if (i < stack_depth_-1) i++;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000706 }
707 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000708 if (instr->IsReturn()) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000709 while (stack_depth_ > 0) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000710 __ fstp(0);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000711 stack_depth_--;
danno@chromium.org169691d2013-07-15 08:01:13 +0000712 }
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000713 if (FLAG_debug_code && FLAG_enable_slow_asserts) __ VerifyX87StackDepth(0);
714 }
715}
716
717
718void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr) {
719 ASSERT(stack_depth_ <= 1);
720 // If ever used for new stubs producing two pairs of doubles joined into two
721 // phis this assert hits. That situation is not handled, since the two stacks
722 // might have st0 and st1 swapped.
723 if (current_block_id + 1 != goto_instr->block_id()) {
724 // If we have a value on the x87 stack on leaving a block, it must be a
725 // phi input. If the next block we compile is not the join block, we have
726 // to discard the stack state.
727 stack_depth_ = 0;
danno@chromium.org169691d2013-07-15 08:01:13 +0000728 }
729}
730
731
732void LCodeGen::EmitFlushX87ForDeopt() {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +0000733 // The deoptimizer does not support X87 Registers. But as long as we
734 // deopt from a stub its not a problem, since we will re-materialize the
735 // original stub inputs, which can't be double registers.
736 ASSERT(info()->IsStub());
737 if (FLAG_debug_code && FLAG_enable_slow_asserts) {
738 __ pushfd();
739 __ VerifyX87StackDepth(x87_stack_.depth());
740 __ popfd();
741 }
742 for (int i = 0; i < x87_stack_.depth(); i++) __ fstp(0);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000743}
744
745
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746Register LCodeGen::ToRegister(LOperand* op) const {
747 ASSERT(op->IsRegister());
748 return ToRegister(op->index());
749}
750
751
danno@chromium.org169691d2013-07-15 08:01:13 +0000752X87Register LCodeGen::ToX87Register(LOperand* op) const {
753 ASSERT(op->IsDoubleRegister());
754 return ToX87Register(op->index());
755}
756
757
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000758XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
759 ASSERT(op->IsDoubleRegister());
760 return ToDoubleRegister(op->index());
761}
762
763
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000764int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
765 return ToRepresentation(op, Representation::Integer32());
766}
767
768
769int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
770 const Representation& r) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000771 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000772 int32_t value = constant->Integer32Value();
773 if (r.IsInteger32()) return value;
774 ASSERT(r.IsSmiOrTagged());
775 return reinterpret_cast<int32_t>(Smi::FromInt(value));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000776}
777
778
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000779Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000780 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000781 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000782 return constant->handle(isolate());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000783}
784
785
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000786double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000787 HConstant* constant = chunk_->LookupConstant(op);
788 ASSERT(constant->HasDoubleValue());
789 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000790}
791
792
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000793ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
794 HConstant* constant = chunk_->LookupConstant(op);
795 ASSERT(constant->HasExternalReferenceValue());
796 return constant->ExternalReferenceValue();
797}
798
799
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000800bool LCodeGen::IsInteger32(LConstantOperand* op) const {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000801 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000802}
803
804
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000805bool LCodeGen::IsSmi(LConstantOperand* op) const {
806 return chunk_->LookupLiteralRepresentation(op).IsSmi();
807}
808
809
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000810static int ArgumentsOffsetWithoutFrame(int index) {
811 ASSERT(index < 0);
812 return -(index + 1) * kPointerSize + kPCOnStackSize;
813}
814
815
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000816Operand LCodeGen::ToOperand(LOperand* op) const {
817 if (op->IsRegister()) return Operand(ToRegister(op));
818 if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
819 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000820 if (NeedsEagerFrame()) {
821 return Operand(ebp, StackSlotOffset(op->index()));
822 } else {
823 // Retrieve parameter without eager stack-frame relative to the
824 // stack-pointer.
825 return Operand(esp, ArgumentsOffsetWithoutFrame(op->index()));
826 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000827}
828
829
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000830Operand LCodeGen::HighOperand(LOperand* op) {
831 ASSERT(op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000832 if (NeedsEagerFrame()) {
833 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
834 } else {
835 // Retrieve parameter without eager stack-frame relative to the
836 // stack-pointer.
837 return Operand(
838 esp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize);
839 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000840}
841
842
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000843void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000844 Translation* translation) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000845 if (environment == NULL) return;
846
847 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000848 int translation_size = environment->translation_size();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000849 // The output frame height does not include the parameters.
850 int height = translation_size - environment->parameter_count();
851
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000852 WriteTranslation(environment->outer(), translation);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000853 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000854 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000855 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000856 ? DefineDeoptimizationLiteral(environment->closure())
857 : Translation::kSelfLiteralId;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000858 switch (environment->frame_type()) {
859 case JS_FUNCTION:
860 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
861 break;
862 case JS_CONSTRUCT:
863 translation->BeginConstructStubFrame(closure_id, translation_size);
864 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000865 case JS_GETTER:
866 ASSERT(translation_size == 1);
867 ASSERT(height == 0);
868 translation->BeginGetterStubFrame(closure_id);
869 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000870 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000871 ASSERT(translation_size == 2);
872 ASSERT(height == 0);
873 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000874 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000875 case ARGUMENTS_ADAPTOR:
876 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
877 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000878 case STUB:
879 translation->BeginCompiledStubFrame();
880 break;
881 default:
882 UNREACHABLE();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000883 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000884
danno@chromium.org59400602013-08-13 17:09:37 +0000885 int object_index = 0;
886 int dematerialized_index = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000887 for (int i = 0; i < translation_size; ++i) {
888 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000889 AddToTranslation(environment,
890 translation,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000891 value,
892 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000893 environment->HasUint32ValueAt(i),
894 &object_index,
895 &dematerialized_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000896 }
897}
898
899
danno@chromium.org59400602013-08-13 17:09:37 +0000900void LCodeGen::AddToTranslation(LEnvironment* environment,
901 Translation* translation,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000902 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000903 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000904 bool is_uint32,
905 int* object_index_pointer,
906 int* dematerialized_index_pointer) {
907 if (op == LEnvironment::materialization_marker()) {
908 int object_index = (*object_index_pointer)++;
909 if (environment->ObjectIsDuplicateAt(object_index)) {
910 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
911 translation->DuplicateObject(dupe_of);
912 return;
913 }
914 int object_length = environment->ObjectLengthAt(object_index);
915 if (environment->ObjectIsArgumentsAt(object_index)) {
916 translation->BeginArgumentsObject(object_length);
917 } else {
918 translation->BeginCapturedObject(object_length);
919 }
920 int dematerialized_index = *dematerialized_index_pointer;
921 int env_offset = environment->translation_size() + dematerialized_index;
922 *dematerialized_index_pointer += object_length;
923 for (int i = 0; i < object_length; ++i) {
924 LOperand* value = environment->values()->at(env_offset + i);
925 AddToTranslation(environment,
926 translation,
927 value,
928 environment->HasTaggedValueAt(env_offset + i),
929 environment->HasUint32ValueAt(env_offset + i),
930 object_index_pointer,
931 dematerialized_index_pointer);
932 }
933 return;
934 }
935
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000936 if (op->IsStackSlot()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000937 if (is_tagged) {
938 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000939 } else if (is_uint32) {
940 translation->StoreUint32StackSlot(op->index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000941 } else {
942 translation->StoreInt32StackSlot(op->index());
943 }
944 } else if (op->IsDoubleStackSlot()) {
945 translation->StoreDoubleStackSlot(op->index());
946 } else if (op->IsArgument()) {
947 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000948 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000949 translation->StoreStackSlot(src_index);
950 } else if (op->IsRegister()) {
951 Register reg = ToRegister(op);
952 if (is_tagged) {
953 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000954 } else if (is_uint32) {
955 translation->StoreUint32Register(reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000956 } else {
957 translation->StoreInt32Register(reg);
958 }
959 } else if (op->IsDoubleRegister()) {
960 XMMRegister reg = ToDoubleRegister(op);
961 translation->StoreDoubleRegister(reg);
962 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000963 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000964 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000965 translation->StoreLiteral(src_index);
966 } else {
967 UNREACHABLE();
968 }
969}
970
971
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000972void LCodeGen::CallCodeGeneric(Handle<Code> code,
973 RelocInfo::Mode mode,
974 LInstruction* instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000975 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000976 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000977 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000978 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000979
980 // Signal that we don't inline smi code before these stubs in the
981 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000982 if (code->kind() == Code::BINARY_OP_IC ||
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000983 code->kind() == Code::COMPARE_IC) {
984 __ nop();
985 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000986}
987
988
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000989void LCodeGen::CallCode(Handle<Code> code,
990 RelocInfo::Mode mode,
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000991 LInstruction* instr) {
992 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000993}
994
995
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996void LCodeGen::CallRuntime(const Runtime::Function* fun,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000997 int argc,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000998 LInstruction* instr,
999 SaveFPRegsMode save_doubles) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001000 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001001 ASSERT(instr->HasPointerMap());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001002
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001003 __ CallRuntime(fun, argc, save_doubles);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001004
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001005 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001006
1007 ASSERT(info()->is_calling());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001008}
1009
1010
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001011void LCodeGen::LoadContextFromDeferred(LOperand* context) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001012 if (context->IsRegister()) {
1013 if (!ToRegister(context).is(esi)) {
1014 __ mov(esi, ToRegister(context));
1015 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001016 } else if (context->IsStackSlot()) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001017 __ mov(esi, ToOperand(context));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001018 } else if (context->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001019 HConstant* constant =
1020 chunk_->LookupConstant(LConstantOperand::cast(context));
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001021 __ LoadObject(esi, Handle<Object>::cast(constant->handle(isolate())));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001022 } else {
1023 UNREACHABLE();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001024 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001025}
1026
1027void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
1028 int argc,
1029 LInstruction* instr,
1030 LOperand* context) {
1031 LoadContextFromDeferred(context);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001032
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001033 __ CallRuntimeSaveDoubles(id);
1034 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001035 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001036
1037 ASSERT(info()->is_calling());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001038}
1039
1040
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001041void LCodeGen::RegisterEnvironmentForDeoptimization(
1042 LEnvironment* environment, Safepoint::DeoptMode mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001043 if (!environment->HasBeenRegistered()) {
1044 // Physical stack frame layout:
1045 // -x ............. -4 0 ..................................... y
1046 // [incoming arguments] [spill slots] [pushed outgoing arguments]
1047
1048 // Layout of the environment:
1049 // 0 ..................................................... size-1
1050 // [parameters] [locals] [expression stack including arguments]
1051
1052 // Layout of the translation:
1053 // 0 ........................................................ size - 1 + 4
1054 // [expression stack including arguments] [locals] [4 words] [parameters]
1055 // |>------------ translation_size ------------<|
1056
1057 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001058 int jsframe_count = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001059 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
1060 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +00001061 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001062 ++jsframe_count;
1063 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001065 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001066 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001067 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001068 int pc_offset = masm()->pc_offset();
1069 environment->Register(deoptimization_index,
1070 translation.index(),
1071 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001072 deoptimizations_.Add(environment, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001073 }
1074}
1075
1076
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001077void LCodeGen::DeoptimizeIf(Condition cc,
1078 LEnvironment* environment,
1079 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001080 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001081 ASSERT(environment->HasBeenRegistered());
1082 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001083 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001084 Address entry =
1085 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001086 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +00001087 Abort(kBailoutWasNotPrepared);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001088 return;
1089 }
1090
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001091 if (DeoptEveryNTimes()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001092 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001093 Label no_deopt;
1094 __ pushfd();
1095 __ push(eax);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001096 __ mov(eax, Operand::StaticVariable(count));
1097 __ sub(eax, Immediate(1));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001098 __ j(not_zero, &no_deopt, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001099 if (FLAG_trap_on_deopt) __ int3();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001100 __ mov(eax, Immediate(FLAG_deopt_every_n_times));
1101 __ mov(Operand::StaticVariable(count), eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001102 __ pop(eax);
1103 __ popfd();
jkummerow@chromium.org10480472013-07-17 08:22:15 +00001104 ASSERT(frame_is_built_);
1105 __ call(entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001106 __ bind(&no_deopt);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001107 __ mov(Operand::StaticVariable(count), eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001108 __ pop(eax);
1109 __ popfd();
1110 }
1111
danno@chromium.org169691d2013-07-15 08:01:13 +00001112 // Before Instructions which can deopt, we normally flush the x87 stack. But
1113 // we can have inputs or outputs of the current instruction on the stack,
1114 // thus we need to flush them here from the physical stack to leave it in a
1115 // consistent state.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001116 if (x87_stack_.depth() > 0) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001117 Label done;
1118 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
1119 EmitFlushX87ForDeopt();
1120 __ bind(&done);
1121 }
1122
danno@chromium.org59400602013-08-13 17:09:37 +00001123 if (info()->ShouldTrapOnDeopt()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001124 Label done;
danno@chromium.org169691d2013-07-15 08:01:13 +00001125 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001126 __ int3();
1127 __ bind(&done);
1128 }
1129
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001130 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001131 if (cc == no_condition && frame_is_built_) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001132 __ call(entry, RelocInfo::RUNTIME_ENTRY);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001133 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001134 // We often have several deopts to the same entry, reuse the last
1135 // jump entry if this is the case.
1136 if (jump_table_.is_empty() ||
1137 jump_table_.last().address != entry ||
1138 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001139 jump_table_.last().bailout_type != bailout_type) {
1140 Deoptimizer::JumpTableEntry table_entry(entry,
1141 bailout_type,
1142 !frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001143 jump_table_.Add(table_entry, zone());
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001144 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001145 if (cc == no_condition) {
1146 __ jmp(&jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001147 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001148 __ j(cc, &jump_table_.last().label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001149 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001150 }
1151}
1152
1153
danno@chromium.orgaefd6072013-05-14 14:11:47 +00001154void LCodeGen::DeoptimizeIf(Condition cc,
1155 LEnvironment* environment) {
1156 Deoptimizer::BailoutType bailout_type = info()->IsStub()
1157 ? Deoptimizer::LAZY
1158 : Deoptimizer::EAGER;
1159 DeoptimizeIf(cc, environment, bailout_type);
1160}
1161
1162
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001163void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
1164 int length = deoptimizations_.length();
1165 if (length == 0) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001166 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001168
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00001169 Handle<ByteArray> translations =
1170 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001171 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001172 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
1173
1174 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001175 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001176 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001177 for (int i = 0; i < deoptimization_literals_.length(); i++) {
1178 literals->set(i, *deoptimization_literals_[i]);
1179 }
1180 data->SetLiteralArray(*literals);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001181 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001182
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001183 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001184 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
1185
1186 // Populate the deoptimization entries.
1187 for (int i = 0; i < length; i++) {
1188 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001189 data->SetAstId(i, env->ast_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001190 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
1191 data->SetArgumentsStackHeight(i,
1192 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001193 data->SetPc(i, Smi::FromInt(env->pc_offset()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001194 }
1195 code->set_deoptimization_data(*data);
1196}
1197
1198
1199int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
1200 int result = deoptimization_literals_.length();
1201 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
1202 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
1203 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001204 deoptimization_literals_.Add(literal, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001205 return result;
1206}
1207
1208
1209void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
1210 ASSERT(deoptimization_literals_.length() == 0);
1211
1212 const ZoneList<Handle<JSFunction> >* inlined_closures =
1213 chunk()->inlined_closures();
1214
1215 for (int i = 0, length = inlined_closures->length();
1216 i < length;
1217 i++) {
1218 DefineDeoptimizationLiteral(inlined_closures->at(i));
1219 }
1220
1221 inlined_function_count_ = deoptimization_literals_.length();
1222}
1223
1224
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001225void LCodeGen::RecordSafepointWithLazyDeopt(
1226 LInstruction* instr, SafepointMode safepoint_mode) {
1227 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
1228 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
1229 } else {
1230 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
1231 RecordSafepointWithRegisters(
1232 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
1233 }
1234}
1235
1236
ager@chromium.org378b34e2011-01-28 08:04:38 +00001237void LCodeGen::RecordSafepoint(
1238 LPointerMap* pointers,
1239 Safepoint::Kind kind,
1240 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001241 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001242 ASSERT(kind == expected_safepoint_kind_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001243 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001244 Safepoint safepoint =
1245 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001246 for (int i = 0; i < operands->length(); i++) {
1247 LOperand* pointer = operands->at(i);
1248 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001249 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +00001250 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001251 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001252 }
1253 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00001254}
1255
1256
1257void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001258 Safepoint::DeoptMode mode) {
1259 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001260}
1261
1262
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001263void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001264 LPointerMap empty_pointers(zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001265 RecordSafepoint(&empty_pointers, mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001266}
1267
1268
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001269void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1270 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001271 Safepoint::DeoptMode mode) {
1272 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001273}
1274
1275
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001276void LCodeGen::RecordAndWritePosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001277 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001278 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00001279 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +00001280}
1281
1282
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001283static const char* LabelType(LLabel* label) {
1284 if (label->is_loop_header()) return " (loop header)";
1285 if (label->is_osr_entry()) return " (OSR entry)";
1286 return "";
1287}
1288
1289
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001290void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001291 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
1292 current_instruction_,
1293 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001294 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001295 LabelType(label));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001296 __ bind(label->label());
1297 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001298 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001299}
1300
1301
1302void LCodeGen::DoParallelMove(LParallelMove* move) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001303 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001304}
1305
1306
1307void LCodeGen::DoGap(LGap* gap) {
1308 for (int i = LGap::FIRST_INNER_POSITION;
1309 i <= LGap::LAST_INNER_POSITION;
1310 i++) {
1311 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1312 LParallelMove* move = gap->GetParallelMove(inner_pos);
1313 if (move != NULL) DoParallelMove(move);
1314 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001315}
1316
1317
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001318void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1319 DoGap(instr);
1320}
1321
1322
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001323void LCodeGen::DoParameter(LParameter* instr) {
1324 // Nothing to do.
1325}
1326
1327
1328void LCodeGen::DoCallStub(LCallStub* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001329 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001330 ASSERT(ToRegister(instr->result()).is(eax));
1331 switch (instr->hydrogen()->major_key()) {
1332 case CodeStub::RegExpConstructResult: {
1333 RegExpConstructResultStub 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::RegExpExec: {
1338 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001339 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001340 break;
1341 }
1342 case CodeStub::SubString: {
1343 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001344 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345 break;
1346 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001347 case CodeStub::StringCompare: {
1348 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001349 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001350 break;
1351 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352 default:
1353 UNREACHABLE();
1354 }
1355}
1356
1357
1358void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001359 GenerateOsrPrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001360}
1361
1362
1363void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001364 HMod* hmod = instr->hydrogen();
1365 HValue* left = hmod->left();
1366 HValue* right = hmod->right();
1367 if (hmod->HasPowerOf2Divisor()) {
1368 // TODO(svenpanne) We should really do the strength reduction on the
1369 // Hydrogen level.
1370 Register left_reg = ToRegister(instr->left());
1371 ASSERT(left_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001372
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001373 // Note: The code below even works when right contains kMinInt.
1374 int32_t divisor = Abs(right->GetInteger32Constant());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001375
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001376 Label left_is_not_negative, done;
1377 if (left->CanBeNegative()) {
1378 __ test(left_reg, Operand(left_reg));
1379 __ j(not_sign, &left_is_not_negative, Label::kNear);
1380 __ neg(left_reg);
1381 __ and_(left_reg, divisor - 1);
1382 __ neg(left_reg);
1383 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1384 DeoptimizeIf(zero, instr->environment());
1385 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001386 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001387 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001388
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001389 __ bind(&left_is_not_negative);
1390 __ and_(left_reg, divisor - 1);
1391 __ bind(&done);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001392 } else {
1393 Register left_reg = ToRegister(instr->left());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001394 ASSERT(left_reg.is(eax));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001395 Register right_reg = ToRegister(instr->right());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001396 ASSERT(!right_reg.is(eax));
1397 ASSERT(!right_reg.is(edx));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001398 Register result_reg = ToRegister(instr->result());
1399 ASSERT(result_reg.is(edx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001400
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001401 Label done;
1402 // Check for x % 0, idiv would signal a divide error. We have to
1403 // deopt in this case because we can't return a NaN.
1404 if (right->CanBeZero()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001405 __ test(right_reg, Operand(right_reg));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001406 DeoptimizeIf(zero, instr->environment());
1407 }
1408
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001409 // Check for kMinInt % -1, idiv would signal a divide error. We
1410 // have to deopt if we care about -0, because we can't return that.
1411 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1412 Label no_overflow_possible;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001413 __ cmp(left_reg, kMinInt);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001414 __ j(not_equal, &no_overflow_possible, Label::kNear);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001415 __ cmp(right_reg, -1);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001416 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1417 DeoptimizeIf(equal, instr->environment());
1418 } else {
1419 __ j(not_equal, &no_overflow_possible, Label::kNear);
1420 __ Set(result_reg, Immediate(0));
1421 __ jmp(&done, Label::kNear);
1422 }
1423 __ bind(&no_overflow_possible);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001424 }
1425
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001426 // Sign extend dividend in eax into edx:eax.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001427 __ cdq();
1428
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001429 // If we care about -0, test if the dividend is <0 and the result is 0.
1430 if (left->CanBeNegative() &&
1431 hmod->CanBeZero() &&
1432 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001433 Label positive_left;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001434 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001435 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001436 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001437 __ test(result_reg, Operand(result_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001438 DeoptimizeIf(zero, instr->environment());
1439 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001440 __ bind(&positive_left);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001441 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001442 __ idiv(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001443 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001444 }
1445}
1446
1447
1448void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001449 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001450 Register dividend = ToRegister(instr->left());
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001451 int32_t divisor = instr->hydrogen()->right()->GetInteger32Constant();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001452 int32_t test_value = 0;
1453 int32_t power = 0;
1454
1455 if (divisor > 0) {
1456 test_value = divisor - 1;
1457 power = WhichPowerOf2(divisor);
1458 } else {
1459 // Check for (0 / -x) that will produce negative zero.
1460 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1461 __ test(dividend, Operand(dividend));
1462 DeoptimizeIf(zero, instr->environment());
1463 }
1464 // Check for (kMinInt / -1).
1465 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1466 __ cmp(dividend, kMinInt);
1467 DeoptimizeIf(zero, instr->environment());
1468 }
1469 test_value = - divisor - 1;
1470 power = WhichPowerOf2(-divisor);
1471 }
1472
1473 if (test_value != 0) {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001474 if (instr->hydrogen()->CheckFlag(
1475 HInstruction::kAllUsesTruncatingToInt32)) {
1476 Label done, negative;
1477 __ cmp(dividend, 0);
1478 __ j(less, &negative, Label::kNear);
1479 __ sar(dividend, power);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001480 if (divisor < 0) __ neg(dividend);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001481 __ jmp(&done, Label::kNear);
1482
1483 __ bind(&negative);
1484 __ neg(dividend);
1485 __ sar(dividend, power);
1486 if (divisor > 0) __ neg(dividend);
1487 __ bind(&done);
1488 return; // Don't fall through to "__ neg" below.
1489 } else {
1490 // Deoptimize if remainder is not 0.
1491 __ test(dividend, Immediate(test_value));
1492 DeoptimizeIf(not_zero, instr->environment());
1493 __ sar(dividend, power);
1494 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001495 }
1496
1497 if (divisor < 0) __ neg(dividend);
1498
1499 return;
1500 }
1501
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001502 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001503 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001504 ASSERT(ToRegister(instr->left()).is(eax));
1505 ASSERT(!ToRegister(instr->right()).is(eax));
1506 ASSERT(!ToRegister(instr->right()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001507
1508 Register left_reg = eax;
1509
1510 // Check for x / 0.
1511 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001512 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001513 __ test(right_reg, ToOperand(right));
1514 DeoptimizeIf(zero, instr->environment());
1515 }
1516
1517 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001518 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001519 Label left_not_zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520 __ test(left_reg, Operand(left_reg));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001521 __ j(not_zero, &left_not_zero, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 __ test(right_reg, ToOperand(right));
1523 DeoptimizeIf(sign, instr->environment());
1524 __ bind(&left_not_zero);
1525 }
1526
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001527 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001528 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001529 Label left_not_min_int;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001530 __ cmp(left_reg, kMinInt);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001531 __ j(not_zero, &left_not_min_int, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001532 __ cmp(right_reg, -1);
1533 DeoptimizeIf(zero, instr->environment());
1534 __ bind(&left_not_min_int);
1535 }
1536
1537 // Sign extend to edx.
1538 __ cdq();
1539 __ idiv(right_reg);
1540
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001541 if (instr->is_flooring()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001542 Label done;
1543 __ test(edx, edx);
1544 __ j(zero, &done, Label::kNear);
1545 __ xor_(edx, right_reg);
1546 __ sar(edx, 31);
1547 __ add(eax, edx);
1548 __ bind(&done);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001549 } else if (!instr->hydrogen()->CheckFlag(
1550 HInstruction::kAllUsesTruncatingToInt32)) {
1551 // Deoptimize if remainder is not 0.
1552 __ test(edx, Operand(edx));
1553 DeoptimizeIf(not_zero, instr->environment());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001554 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001555}
1556
1557
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001558void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001559 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001560
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001561 Register dividend = ToRegister(instr->left());
1562 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001563 Register result = ToRegister(instr->result());
1564
1565 switch (divisor) {
1566 case 0:
1567 DeoptimizeIf(no_condition, instr->environment());
1568 return;
1569
1570 case 1:
1571 __ Move(result, dividend);
1572 return;
1573
1574 case -1:
1575 __ Move(result, dividend);
1576 __ neg(result);
1577 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1578 DeoptimizeIf(zero, instr->environment());
1579 }
1580 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1581 DeoptimizeIf(overflow, instr->environment());
1582 }
1583 return;
1584 }
1585
1586 uint32_t divisor_abs = abs(divisor);
1587 if (IsPowerOf2(divisor_abs)) {
1588 int32_t power = WhichPowerOf2(divisor_abs);
1589 if (divisor < 0) {
1590 // Input[dividend] is clobbered.
1591 // The sequence is tedious because neg(dividend) might overflow.
1592 __ mov(result, dividend);
1593 __ sar(dividend, 31);
1594 __ neg(result);
1595 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1596 DeoptimizeIf(zero, instr->environment());
1597 }
1598 __ shl(dividend, 32 - power);
1599 __ sar(result, power);
1600 __ not_(dividend);
1601 // Clear result.sign if dividend.sign is set.
1602 __ and_(result, dividend);
1603 } else {
1604 __ Move(result, dividend);
1605 __ sar(result, power);
1606 }
1607 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001608 ASSERT(ToRegister(instr->left()).is(eax));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001609 ASSERT(ToRegister(instr->result()).is(edx));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001610 Register scratch = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001611
1612 // Find b which: 2^b < divisor_abs < 2^(b+1).
1613 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1614 unsigned shift = 32 + b; // Precision +1bit (effectively).
1615 double multiplier_f =
1616 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1617 int64_t multiplier;
1618 if (multiplier_f - floor(multiplier_f) < 0.5) {
1619 multiplier = static_cast<int64_t>(floor(multiplier_f));
1620 } else {
1621 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1622 }
1623 // The multiplier is a uint32.
1624 ASSERT(multiplier > 0 &&
1625 multiplier < (static_cast<int64_t>(1) << 32));
1626 __ mov(scratch, dividend);
1627 if (divisor < 0 &&
1628 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1629 __ test(dividend, dividend);
1630 DeoptimizeIf(zero, instr->environment());
1631 }
1632 __ mov(edx, static_cast<int32_t>(multiplier));
1633 __ imul(edx);
1634 if (static_cast<int32_t>(multiplier) < 0) {
1635 __ add(edx, scratch);
1636 }
1637 Register reg_lo = eax;
1638 Register reg_byte_scratch = scratch;
1639 if (!reg_byte_scratch.is_byte_register()) {
1640 __ xchg(reg_lo, reg_byte_scratch);
1641 reg_lo = scratch;
1642 reg_byte_scratch = eax;
1643 }
1644 if (divisor < 0) {
1645 __ xor_(reg_byte_scratch, reg_byte_scratch);
1646 __ cmp(reg_lo, 0x40000000);
1647 __ setcc(above, reg_byte_scratch);
1648 __ neg(edx);
1649 __ sub(edx, reg_byte_scratch);
1650 } else {
1651 __ xor_(reg_byte_scratch, reg_byte_scratch);
1652 __ cmp(reg_lo, 0xC0000000);
1653 __ setcc(above_equal, reg_byte_scratch);
1654 __ add(edx, reg_byte_scratch);
1655 }
1656 __ sar(edx, shift - 32);
1657 }
1658}
1659
1660
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001661void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001662 Register left = ToRegister(instr->left());
1663 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001664
1665 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001666 __ mov(ToRegister(instr->temp()), left);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001667 }
1668
1669 if (right->IsConstantOperand()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001670 // Try strength reductions on the multiplication.
1671 // All replacement instructions are at most as long as the imul
1672 // and have better latency.
1673 int constant = ToInteger32(LConstantOperand::cast(right));
1674 if (constant == -1) {
1675 __ neg(left);
1676 } else if (constant == 0) {
1677 __ xor_(left, Operand(left));
1678 } else if (constant == 2) {
1679 __ add(left, Operand(left));
1680 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1681 // If we know that the multiplication can't overflow, it's safe to
1682 // use instructions that don't set the overflow flag for the
1683 // multiplication.
1684 switch (constant) {
1685 case 1:
1686 // Do nothing.
1687 break;
1688 case 3:
1689 __ lea(left, Operand(left, left, times_2, 0));
1690 break;
1691 case 4:
1692 __ shl(left, 2);
1693 break;
1694 case 5:
1695 __ lea(left, Operand(left, left, times_4, 0));
1696 break;
1697 case 8:
1698 __ shl(left, 3);
1699 break;
1700 case 9:
1701 __ lea(left, Operand(left, left, times_8, 0));
1702 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001703 case 16:
1704 __ shl(left, 4);
1705 break;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00001706 default:
1707 __ imul(left, left, constant);
1708 break;
1709 }
1710 } else {
1711 __ imul(left, left, constant);
1712 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001713 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001714 if (instr->hydrogen()->representation().IsSmi()) {
1715 __ SmiUntag(left);
1716 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001717 __ imul(left, ToOperand(right));
1718 }
1719
1720 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1721 DeoptimizeIf(overflow, instr->environment());
1722 }
1723
1724 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1725 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001726 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001727 __ test(left, Operand(left));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001728 __ j(not_zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001729 if (right->IsConstantOperand()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001730 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001731 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001732 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1733 __ cmp(ToRegister(instr->temp()), Immediate(0));
1734 DeoptimizeIf(less, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001735 }
1736 } else {
1737 // Test the non-zero operand for negative sign.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001738 __ or_(ToRegister(instr->temp()), ToOperand(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001739 DeoptimizeIf(sign, instr->environment());
1740 }
1741 __ bind(&done);
1742 }
1743}
1744
1745
1746void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001747 LOperand* left = instr->left();
1748 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001749 ASSERT(left->Equals(instr->result()));
1750 ASSERT(left->IsRegister());
1751
1752 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001753 int32_t right_operand =
1754 ToRepresentation(LConstantOperand::cast(right),
1755 instr->hydrogen()->representation());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001756 switch (instr->op()) {
1757 case Token::BIT_AND:
1758 __ and_(ToRegister(left), right_operand);
1759 break;
1760 case Token::BIT_OR:
1761 __ or_(ToRegister(left), right_operand);
1762 break;
1763 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001764 if (right_operand == int32_t(~0)) {
1765 __ not_(ToRegister(left));
1766 } else {
1767 __ xor_(ToRegister(left), right_operand);
1768 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001769 break;
1770 default:
1771 UNREACHABLE();
1772 break;
1773 }
1774 } else {
1775 switch (instr->op()) {
1776 case Token::BIT_AND:
1777 __ and_(ToRegister(left), ToOperand(right));
1778 break;
1779 case Token::BIT_OR:
1780 __ or_(ToRegister(left), ToOperand(right));
1781 break;
1782 case Token::BIT_XOR:
1783 __ xor_(ToRegister(left), ToOperand(right));
1784 break;
1785 default:
1786 UNREACHABLE();
1787 break;
1788 }
1789 }
1790}
1791
1792
1793void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001794 LOperand* left = instr->left();
1795 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001796 ASSERT(left->Equals(instr->result()));
1797 ASSERT(left->IsRegister());
1798 if (right->IsRegister()) {
1799 ASSERT(ToRegister(right).is(ecx));
1800
1801 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001802 case Token::ROR:
1803 __ ror_cl(ToRegister(left));
1804 if (instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001805 __ test(ToRegister(left), ToRegister(left));
1806 DeoptimizeIf(sign, instr->environment());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001807 }
1808 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001809 case Token::SAR:
1810 __ sar_cl(ToRegister(left));
1811 break;
1812 case Token::SHR:
1813 __ shr_cl(ToRegister(left));
1814 if (instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001815 __ test(ToRegister(left), ToRegister(left));
1816 DeoptimizeIf(sign, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001817 }
1818 break;
1819 case Token::SHL:
1820 __ shl_cl(ToRegister(left));
1821 break;
1822 default:
1823 UNREACHABLE();
1824 break;
1825 }
1826 } else {
1827 int value = ToInteger32(LConstantOperand::cast(right));
1828 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1829 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001830 case Token::ROR:
1831 if (shift_count == 0 && instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001832 __ test(ToRegister(left), ToRegister(left));
1833 DeoptimizeIf(sign, instr->environment());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001834 } else {
1835 __ ror(ToRegister(left), shift_count);
1836 }
1837 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001838 case Token::SAR:
1839 if (shift_count != 0) {
1840 __ sar(ToRegister(left), shift_count);
1841 }
1842 break;
1843 case Token::SHR:
1844 if (shift_count == 0 && instr->can_deopt()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00001845 __ test(ToRegister(left), ToRegister(left));
1846 DeoptimizeIf(sign, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001847 } else {
1848 __ shr(ToRegister(left), shift_count);
1849 }
1850 break;
1851 case Token::SHL:
1852 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001853 if (instr->hydrogen_value()->representation().IsSmi() &&
1854 instr->can_deopt()) {
1855 if (shift_count != 1) {
1856 __ shl(ToRegister(left), shift_count - 1);
1857 }
1858 __ SmiTag(ToRegister(left));
1859 DeoptimizeIf(overflow, instr->environment());
1860 } else {
1861 __ shl(ToRegister(left), shift_count);
1862 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001863 }
1864 break;
1865 default:
1866 UNREACHABLE();
1867 break;
1868 }
1869 }
1870}
1871
1872
1873void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001874 LOperand* left = instr->left();
1875 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001876 ASSERT(left->Equals(instr->result()));
1877
1878 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001879 __ sub(ToOperand(left),
1880 ToImmediate(right, instr->hydrogen()->representation()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001881 } else {
1882 __ sub(ToRegister(left), ToOperand(right));
1883 }
1884 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1885 DeoptimizeIf(overflow, instr->environment());
1886 }
1887}
1888
1889
1890void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001891 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
1892}
1893
1894
1895void LCodeGen::DoConstantS(LConstantS* instr) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001896 __ Set(ToRegister(instr->result()), Immediate(instr->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001897}
1898
1899
1900void LCodeGen::DoConstantD(LConstantD* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001901 double v = instr->value();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001902 uint64_t int_val = BitCast<uint64_t, double>(v);
1903 int32_t lower = static_cast<int32_t>(int_val);
1904 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001905 ASSERT(instr->result()->IsDoubleRegister());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001906
1907 if (!CpuFeatures::IsSafeForSnapshot(SSE2)) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001908 __ push(Immediate(upper));
danno@chromium.org169691d2013-07-15 08:01:13 +00001909 __ push(Immediate(lower));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001910 X87Register reg = ToX87Register(instr->result());
1911 X87Mov(reg, Operand(esp, 0));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001912 __ add(Operand(esp), Immediate(kDoubleSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001913 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001914 CpuFeatureScope scope1(masm(), SSE2);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001915 XMMRegister res = ToDoubleRegister(instr->result());
1916 if (int_val == 0) {
1917 __ xorps(res, res);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001918 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001919 Register temp = ToRegister(instr->temp());
1920 if (CpuFeatures::IsSupported(SSE4_1)) {
1921 CpuFeatureScope scope2(masm(), SSE4_1);
1922 if (lower != 0) {
1923 __ Set(temp, Immediate(lower));
1924 __ movd(res, Operand(temp));
1925 __ Set(temp, Immediate(upper));
1926 __ pinsrd(res, Operand(temp), 1);
1927 } else {
1928 __ xorps(res, res);
1929 __ Set(temp, Immediate(upper));
1930 __ pinsrd(res, Operand(temp), 1);
1931 }
1932 } else {
1933 __ Set(temp, Immediate(upper));
1934 __ movd(res, Operand(temp));
1935 __ psllq(res, 32);
1936 if (lower != 0) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001937 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001938 __ Set(temp, Immediate(lower));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001939 __ movd(xmm_scratch, Operand(temp));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001940 __ orps(res, xmm_scratch);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001941 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001942 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001943 }
1944 }
1945}
1946
1947
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001948void LCodeGen::DoConstantE(LConstantE* instr) {
1949 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value()));
1950}
1951
1952
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001953void LCodeGen::DoConstantT(LConstantT* instr) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001954 Register reg = ToRegister(instr->result());
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001955 Handle<Object> handle = instr->value(isolate());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001956 AllowDeferredHandleDereference smi_check;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001957 __ LoadObject(reg, handle);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001958}
1959
1960
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001961void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1962 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001963 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001964 __ EnumLength(result, map);
1965}
1966
1967
whesse@chromium.org7b260152011-06-20 15:33:18 +00001968void LCodeGen::DoElementsKind(LElementsKind* instr) {
1969 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001970 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001971
1972 // Load map into |result|.
1973 __ mov(result, FieldOperand(input, HeapObject::kMapOffset));
1974 // Load the map's "bit field 2" into |result|. We only need the first byte,
1975 // but the following masking takes care of that anyway.
1976 __ mov(result, FieldOperand(result, Map::kBitField2Offset));
1977 // Retrieve elements_kind from bit field 2.
1978 __ and_(result, Map::kElementsKindMask);
1979 __ shr(result, Map::kElementsKindShift);
1980}
1981
1982
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001983void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001984 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001985 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001986 Register map = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001987 ASSERT(input.is(result));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001988
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001989 Label done;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001990
1991 if (!instr->hydrogen()->value()->IsHeapObject()) {
1992 // If the object is a smi return the object.
1993 __ JumpIfSmi(input, &done, Label::kNear);
1994 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995
1996 // If the object is not a value type, return the object.
1997 __ CmpObjectType(input, JS_VALUE_TYPE, map);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001998 __ j(not_equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001999 __ mov(result, FieldOperand(input, JSValue::kValueOffset));
2000
2001 __ bind(&done);
2002}
2003
2004
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002005void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002006 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002007 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002008 Register scratch = ToRegister(instr->temp());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002009 Smi* index = instr->index();
2010 Label runtime, done;
2011 ASSERT(object.is(result));
2012 ASSERT(object.is(eax));
2013
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002014 __ test(object, Immediate(kSmiTagMask));
2015 DeoptimizeIf(zero, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002016 __ CmpObjectType(object, JS_DATE_TYPE, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002017 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002018
2019 if (index->value() == 0) {
2020 __ mov(result, FieldOperand(object, JSDate::kValueOffset));
2021 } else {
2022 if (index->value() < JSDate::kFirstUncachedField) {
2023 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
2024 __ mov(scratch, Operand::StaticVariable(stamp));
2025 __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
2026 __ j(not_equal, &runtime, Label::kNear);
2027 __ mov(result, FieldOperand(object, JSDate::kValueOffset +
2028 kPointerSize * index->value()));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002029 __ jmp(&done, Label::kNear);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00002030 }
2031 __ bind(&runtime);
2032 __ PrepareCallCFunction(2, scratch);
2033 __ mov(Operand(esp, 0), object);
2034 __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
2035 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
2036 __ bind(&done);
2037 }
2038}
2039
2040
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002041Operand LCodeGen::BuildSeqStringOperand(Register string,
2042 LOperand* index,
2043 String::Encoding encoding) {
2044 if (index->IsConstantOperand()) {
2045 int offset = ToRepresentation(LConstantOperand::cast(index),
2046 Representation::Integer32());
2047 if (encoding == String::TWO_BYTE_ENCODING) {
2048 offset *= kUC16Size;
2049 }
2050 STATIC_ASSERT(kCharSize == 1);
2051 return FieldOperand(string, SeqString::kHeaderSize + offset);
2052 }
2053 return FieldOperand(
2054 string, ToRegister(index),
2055 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
2056 SeqString::kHeaderSize);
2057}
2058
2059
2060void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
2061 String::Encoding encoding = instr->hydrogen()->encoding();
2062 Register result = ToRegister(instr->result());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002063 Register string = ToRegister(instr->string());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002064
2065 if (FLAG_debug_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002066 __ push(string);
2067 __ mov(string, FieldOperand(string, HeapObject::kMapOffset));
2068 __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002069
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002070 __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002071 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
2072 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002073 __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING
2074 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00002075 __ Check(equal, kUnexpectedStringType);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002076 __ pop(string);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002077 }
2078
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002079 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002080 if (encoding == String::ONE_BYTE_ENCODING) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002081 __ movzx_b(result, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002082 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002083 __ movzx_w(result, operand);
2084 }
2085}
2086
2087
2088void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
2089 String::Encoding encoding = instr->hydrogen()->encoding();
2090 Register string = ToRegister(instr->string());
2091
2092 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002093 Register value = ToRegister(instr->value());
2094 Register index = ToRegister(instr->index());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002095 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
2096 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002097 int encoding_mask =
2098 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
2099 ? one_byte_seq_type : two_byte_seq_type;
2100 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002101 }
2102
2103 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
2104 if (instr->value()->IsConstantOperand()) {
2105 int value = ToRepresentation(LConstantOperand::cast(instr->value()),
2106 Representation::Integer32());
2107 ASSERT_LE(0, value);
2108 if (encoding == String::ONE_BYTE_ENCODING) {
2109 ASSERT_LE(value, String::kMaxOneByteCharCode);
2110 __ mov_b(operand, static_cast<int8_t>(value));
2111 } else {
2112 ASSERT_LE(value, String::kMaxUtf16CodeUnit);
2113 __ mov_w(operand, static_cast<int16_t>(value));
2114 }
2115 } else {
2116 Register value = ToRegister(instr->value());
2117 if (encoding == String::ONE_BYTE_ENCODING) {
2118 __ mov_b(operand, value);
2119 } else {
2120 __ mov_w(operand, value);
2121 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002122 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002123}
2124
2125
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002126void LCodeGen::DoThrow(LThrow* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002127 __ push(ToOperand(instr->value()));
2128 ASSERT(ToRegister(instr->context()).is(esi));
2129 CallRuntime(Runtime::kThrow, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002130
2131 if (FLAG_debug_code) {
2132 Comment("Unreachable code.");
2133 __ int3();
2134 }
2135}
2136
2137
2138void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002139 LOperand* left = instr->left();
2140 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002141
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002142 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
2143 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002144 int32_t offset = ToRepresentation(LConstantOperand::cast(right),
2145 instr->hydrogen()->representation());
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002146 __ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset));
2147 } else {
2148 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
2149 __ lea(ToRegister(instr->result()), address);
2150 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002151 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002152 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002153 __ add(ToOperand(left),
2154 ToImmediate(right, instr->hydrogen()->representation()));
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002155 } else {
2156 __ add(ToRegister(left), ToOperand(right));
2157 }
2158 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
2159 DeoptimizeIf(overflow, instr->environment());
2160 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002161 }
2162}
2163
2164
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002165void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002166 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002167 LOperand* left = instr->left();
2168 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002169 ASSERT(left->Equals(instr->result()));
2170 HMathMinMax::Operation operation = instr->hydrogen()->operation();
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002171 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002172 Label return_left;
2173 Condition condition = (operation == HMathMinMax::kMathMin)
2174 ? less_equal
2175 : greater_equal;
2176 if (right->IsConstantOperand()) {
2177 Operand left_op = ToOperand(left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002178 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->right()),
2179 instr->hydrogen()->representation());
2180 __ cmp(left_op, immediate);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002181 __ j(condition, &return_left, Label::kNear);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002182 __ mov(left_op, immediate);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002183 } else {
2184 Register left_reg = ToRegister(left);
2185 Operand right_op = ToOperand(right);
2186 __ cmp(left_reg, right_op);
2187 __ j(condition, &return_left, Label::kNear);
2188 __ mov(left_reg, right_op);
2189 }
2190 __ bind(&return_left);
2191 } else {
2192 ASSERT(instr->hydrogen()->representation().IsDouble());
2193 Label check_nan_left, check_zero, return_left, return_right;
2194 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
2195 XMMRegister left_reg = ToDoubleRegister(left);
2196 XMMRegister right_reg = ToDoubleRegister(right);
2197 __ ucomisd(left_reg, right_reg);
2198 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
2199 __ j(equal, &check_zero, Label::kNear); // left == right.
2200 __ j(condition, &return_left, Label::kNear);
2201 __ jmp(&return_right, Label::kNear);
2202
2203 __ bind(&check_zero);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002204 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002205 __ xorps(xmm_scratch, xmm_scratch);
2206 __ ucomisd(left_reg, xmm_scratch);
2207 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
2208 // At this point, both left and right are either 0 or -0.
2209 if (operation == HMathMinMax::kMathMin) {
2210 __ orpd(left_reg, right_reg);
2211 } else {
2212 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
2213 __ addsd(left_reg, right_reg);
2214 }
2215 __ jmp(&return_left, Label::kNear);
2216
2217 __ bind(&check_nan_left);
2218 __ ucomisd(left_reg, left_reg); // NaN check.
2219 __ j(parity_even, &return_left, Label::kNear); // left == NaN.
2220 __ bind(&return_right);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002221 __ movaps(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002222
2223 __ bind(&return_left);
2224 }
2225}
2226
2227
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002228void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
danno@chromium.org169691d2013-07-15 08:01:13 +00002229 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2230 CpuFeatureScope scope(masm(), SSE2);
2231 XMMRegister left = ToDoubleRegister(instr->left());
2232 XMMRegister right = ToDoubleRegister(instr->right());
2233 XMMRegister result = ToDoubleRegister(instr->result());
danno@chromium.org169691d2013-07-15 08:01:13 +00002234 switch (instr->op()) {
2235 case Token::ADD:
2236 __ addsd(left, right);
2237 break;
2238 case Token::SUB:
2239 __ subsd(left, right);
2240 break;
2241 case Token::MUL:
2242 __ mulsd(left, right);
2243 break;
2244 case Token::DIV:
2245 __ divsd(left, right);
2246 // Don't delete this mov. It may improve performance on some CPUs,
2247 // when there is a mulsd depending on the result
2248 __ movaps(left, left);
2249 break;
2250 case Token::MOD: {
2251 // Pass two doubles as arguments on the stack.
2252 __ PrepareCallCFunction(4, eax);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002253 __ movsd(Operand(esp, 0 * kDoubleSize), left);
2254 __ movsd(Operand(esp, 1 * kDoubleSize), right);
danno@chromium.org169691d2013-07-15 08:01:13 +00002255 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00002256 ExternalReference::mod_two_doubles_operation(isolate()),
danno@chromium.org169691d2013-07-15 08:01:13 +00002257 4);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002258
danno@chromium.org169691d2013-07-15 08:01:13 +00002259 // Return value is in st(0) on ia32.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002260 // Store it into the result register.
danno@chromium.org169691d2013-07-15 08:01:13 +00002261 __ sub(Operand(esp), Immediate(kDoubleSize));
2262 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002263 __ movsd(result, Operand(esp, 0));
danno@chromium.org169691d2013-07-15 08:01:13 +00002264 __ add(Operand(esp), Immediate(kDoubleSize));
2265 break;
2266 }
2267 default:
2268 UNREACHABLE();
2269 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002270 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002271 } else {
2272 X87Register left = ToX87Register(instr->left());
2273 X87Register right = ToX87Register(instr->right());
2274 X87Register result = ToX87Register(instr->result());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002275 if (instr->op() != Token::MOD) {
2276 X87PrepareBinaryOp(left, right, result);
2277 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002278 switch (instr->op()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002279 case Token::ADD:
2280 __ fadd_i(1);
2281 break;
2282 case Token::SUB:
2283 __ fsub_i(1);
2284 break;
danno@chromium.org169691d2013-07-15 08:01:13 +00002285 case Token::MUL:
2286 __ fmul_i(1);
2287 break;
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002288 case Token::DIV:
2289 __ fdiv_i(1);
2290 break;
2291 case Token::MOD: {
2292 // Pass two doubles as arguments on the stack.
2293 __ PrepareCallCFunction(4, eax);
2294 X87Mov(Operand(esp, 1 * kDoubleSize), right);
2295 X87Mov(Operand(esp, 0), left);
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00002296 X87Free(right);
2297 ASSERT(left.is(result));
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002298 X87PrepareToWrite(result);
2299 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00002300 ExternalReference::mod_two_doubles_operation(isolate()),
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002301 4);
2302
2303 // Return value is in st(0) on ia32.
2304 X87CommitWrite(result);
2305 break;
2306 }
danno@chromium.org169691d2013-07-15 08:01:13 +00002307 default:
2308 UNREACHABLE();
2309 break;
2310 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002311 }
2312}
2313
2314
2315void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002316 ASSERT(ToRegister(instr->context()).is(esi));
2317 ASSERT(ToRegister(instr->left()).is(edx));
2318 ASSERT(ToRegister(instr->right()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002319 ASSERT(ToRegister(instr->result()).is(eax));
2320
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002321 BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002322 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002323 __ nop(); // Signals no inlined code.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002324}
2325
2326
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002327template<class InstrType>
2328void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002329 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002330 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002331
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002332 int next_block = GetNextEmittedBlock();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002333
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002334 if (right_block == left_block || cc == no_condition) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002335 EmitGoto(left_block);
2336 } else if (left_block == next_block) {
2337 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
2338 } else if (right_block == next_block) {
2339 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2340 } else {
2341 __ j(cc, chunk_->GetAssemblyLabel(left_block));
2342 __ jmp(chunk_->GetAssemblyLabel(right_block));
2343 }
2344}
2345
2346
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002347template<class InstrType>
2348void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
2349 int false_block = instr->FalseDestination(chunk_);
2350 if (cc == no_condition) {
2351 __ jmp(chunk_->GetAssemblyLabel(false_block));
2352 } else {
2353 __ j(cc, chunk_->GetAssemblyLabel(false_block));
2354 }
2355}
2356
2357
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002358void LCodeGen::DoBranch(LBranch* instr) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002359 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002360 if (r.IsSmiOrInteger32()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002361 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002362 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002363 EmitBranch(instr, not_zero);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002364 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002365 ASSERT(!info()->IsStub());
2366 CpuFeatureScope scope(masm(), SSE2);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002367 XMMRegister reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002368 XMMRegister xmm_scratch = double_scratch0();
2369 __ xorps(xmm_scratch, xmm_scratch);
2370 __ ucomisd(reg, xmm_scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002371 EmitBranch(instr, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002372 } else {
2373 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002374 Register reg = ToRegister(instr->value());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002375 HType type = instr->hydrogen()->value()->type();
2376 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002377 ASSERT(!info()->IsStub());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002378 __ cmp(reg, factory()->true_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002379 EmitBranch(instr, equal);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002380 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002381 ASSERT(!info()->IsStub());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002382 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002383 EmitBranch(instr, not_equal);
2384 } else if (type.IsJSArray()) {
2385 ASSERT(!info()->IsStub());
2386 EmitBranch(instr, no_condition);
2387 } else if (type.IsHeapNumber()) {
2388 ASSERT(!info()->IsStub());
2389 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002390 XMMRegister xmm_scratch = double_scratch0();
2391 __ xorps(xmm_scratch, xmm_scratch);
2392 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002393 EmitBranch(instr, not_equal);
2394 } else if (type.IsString()) {
2395 ASSERT(!info()->IsStub());
2396 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2397 EmitBranch(instr, not_equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002398 } else {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002399 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002400 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002401
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002402 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2403 // undefined -> false.
2404 __ cmp(reg, factory()->undefined_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002405 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002406 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002407 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2408 // true -> true.
2409 __ cmp(reg, factory()->true_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002410 __ j(equal, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002411 // false -> false.
2412 __ cmp(reg, factory()->false_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002413 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002414 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002415 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2416 // 'null' -> false.
2417 __ cmp(reg, factory()->null_value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002418 __ j(equal, instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002419 }
2420
2421 if (expected.Contains(ToBooleanStub::SMI)) {
2422 // Smis: 0 -> false, all other -> true.
2423 __ test(reg, Operand(reg));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002424 __ j(equal, instr->FalseLabel(chunk_));
2425 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002426 } else if (expected.NeedsMap()) {
2427 // If we need a map later and have a Smi -> deopt.
2428 __ test(reg, Immediate(kSmiTagMask));
2429 DeoptimizeIf(zero, instr->environment());
2430 }
2431
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002432 Register map = no_reg; // Keep the compiler happy.
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002433 if (expected.NeedsMap()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002434 map = ToRegister(instr->temp());
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002435 ASSERT(!map.is(reg));
2436 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002437
2438 if (expected.CanBeUndetectable()) {
2439 // Undetectable -> false.
2440 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
2441 1 << Map::kIsUndetectable);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002442 __ j(not_zero, instr->FalseLabel(chunk_));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002443 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002444 }
2445
2446 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2447 // spec object -> true.
2448 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002449 __ j(above_equal, instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002450 }
2451
2452 if (expected.Contains(ToBooleanStub::STRING)) {
2453 // String value -> false iff empty.
2454 Label not_string;
2455 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2456 __ j(above_equal, &not_string, Label::kNear);
2457 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002458 __ j(not_zero, instr->TrueLabel(chunk_));
2459 __ jmp(instr->FalseLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002460 __ bind(&not_string);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002461 }
2462
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002463 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2464 // Symbol value -> true.
2465 __ CmpInstanceType(map, SYMBOL_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002466 __ j(equal, instr->TrueLabel(chunk_));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002467 }
2468
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002469 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2470 // heap number -> false iff +0, -0, or NaN.
2471 Label not_heap_number;
2472 __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
2473 factory()->heap_number_map());
2474 __ j(not_equal, &not_heap_number, Label::kNear);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002475 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2476 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002477 XMMRegister xmm_scratch = double_scratch0();
2478 __ xorps(xmm_scratch, xmm_scratch);
2479 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002480 } else {
2481 __ fldz();
2482 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset));
2483 __ FCmp();
2484 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002485 __ j(zero, instr->FalseLabel(chunk_));
2486 __ jmp(instr->TrueLabel(chunk_));
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002487 __ bind(&not_heap_number);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00002488 }
2489
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002490 if (!expected.IsGeneric()) {
2491 // We've seen something for the first time -> deopt.
2492 // This can only happen if we are not generic already.
2493 DeoptimizeIf(no_condition, instr->environment());
2494 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002495 }
2496 }
2497}
2498
2499
ager@chromium.org04921a82011-06-27 13:21:41 +00002500void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002501 if (!IsNextEmittedBlock(block)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002502 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503 }
2504}
2505
2506
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00002507void LCodeGen::DoClobberDoubles(LClobberDoubles* instr) {
2508}
2509
2510
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002511void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002512 EmitGoto(instr->block_id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002513}
2514
2515
2516Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2517 Condition cond = no_condition;
2518 switch (op) {
2519 case Token::EQ:
2520 case Token::EQ_STRICT:
2521 cond = equal;
2522 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002523 case Token::NE:
2524 case Token::NE_STRICT:
2525 cond = not_equal;
2526 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002527 case Token::LT:
2528 cond = is_unsigned ? below : less;
2529 break;
2530 case Token::GT:
2531 cond = is_unsigned ? above : greater;
2532 break;
2533 case Token::LTE:
2534 cond = is_unsigned ? below_equal : less_equal;
2535 break;
2536 case Token::GTE:
2537 cond = is_unsigned ? above_equal : greater_equal;
2538 break;
2539 case Token::IN:
2540 case Token::INSTANCEOF:
2541 default:
2542 UNREACHABLE();
2543 }
2544 return cond;
2545}
2546
2547
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002548void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002549 LOperand* left = instr->left();
2550 LOperand* right = instr->right();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002551 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002552
2553 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2554 // We can statically evaluate the comparison.
2555 double left_val = ToDouble(LConstantOperand::cast(left));
2556 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002557 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2558 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002559 EmitGoto(next_block);
2560 } else {
2561 if (instr->is_double()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002562 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
2563 CpuFeatureScope scope(masm(), SSE2);
2564 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
2565 } else {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002566 X87LoadForUsage(ToX87Register(right), ToX87Register(left));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002567 __ FCmp();
2568 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002569 // Don't base result on EFLAGS when a NaN is involved. Instead
2570 // jump to the false block.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002571 __ j(parity_even, instr->FalseLabel(chunk_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002572 } else {
2573 if (right->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002574 __ cmp(ToOperand(left),
2575 ToImmediate(right, instr->hydrogen()->representation()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002576 } else if (left->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002577 __ cmp(ToOperand(right),
2578 ToImmediate(left, instr->hydrogen()->representation()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002579 // We transposed the operands. Reverse the condition.
2580 cc = ReverseCondition(cc);
2581 } else {
2582 __ cmp(ToRegister(left), ToOperand(right));
2583 }
2584 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002585 EmitBranch(instr, cc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002586 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002587}
2588
2589
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002590void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002591 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002592
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002593 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002594 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
2595 __ CmpObject(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002596 } else {
2597 Operand right = ToOperand(instr->right());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002598 __ cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002599 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002600 EmitBranch(instr, equal);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002601}
2602
2603
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002604void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2605 if (instr->hydrogen()->representation().IsTagged()) {
2606 Register input_reg = ToRegister(instr->object());
2607 __ cmp(input_reg, factory()->the_hole_value());
2608 EmitBranch(instr, equal);
2609 return;
2610 }
2611
2612 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
2613 if (use_sse2) {
2614 CpuFeatureScope scope(masm(), SSE2);
2615 XMMRegister input_reg = ToDoubleRegister(instr->object());
2616 __ ucomisd(input_reg, input_reg);
2617 EmitFalseBranch(instr, parity_odd);
2618 } else {
2619 // Put the value to the top of stack
2620 X87Register src = ToX87Register(instr->object());
2621 X87LoadForUsage(src);
2622 __ fld(0);
2623 __ fld(0);
2624 __ FCmp();
2625 Label ok;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002626 __ j(parity_even, &ok, Label::kNear);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002627 __ fstp(0);
2628 EmitFalseBranch(instr, no_condition);
2629 __ bind(&ok);
2630 }
2631
2632
2633 __ sub(esp, Immediate(kDoubleSize));
2634 if (use_sse2) {
2635 CpuFeatureScope scope(masm(), SSE2);
2636 XMMRegister input_reg = ToDoubleRegister(instr->object());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00002637 __ movsd(MemOperand(esp, 0), input_reg);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002638 } else {
2639 __ fstp_d(MemOperand(esp, 0));
2640 }
2641
2642 __ add(esp, Immediate(kDoubleSize));
2643 int offset = sizeof(kHoleNanUpper32);
2644 __ cmp(MemOperand(esp, -offset), Immediate(kHoleNanUpper32));
2645 EmitBranch(instr, equal);
2646}
2647
2648
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002649void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2650 Representation rep = instr->hydrogen()->value()->representation();
2651 ASSERT(!rep.IsInteger32());
2652 Register scratch = ToRegister(instr->temp());
2653
2654 if (rep.IsDouble()) {
2655 CpuFeatureScope use_sse2(masm(), SSE2);
2656 XMMRegister value = ToDoubleRegister(instr->value());
2657 XMMRegister xmm_scratch = double_scratch0();
2658 __ xorps(xmm_scratch, xmm_scratch);
2659 __ ucomisd(xmm_scratch, value);
2660 EmitFalseBranch(instr, not_equal);
2661 __ movmskpd(scratch, value);
2662 __ test(scratch, Immediate(1));
2663 EmitBranch(instr, not_zero);
2664 } else {
2665 Register value = ToRegister(instr->value());
2666 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
2667 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
2668 __ cmp(FieldOperand(value, HeapNumber::kExponentOffset),
2669 Immediate(0x80000000));
2670 EmitFalseBranch(instr, not_equal);
2671 __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset),
2672 Immediate(0x00000000));
2673 EmitBranch(instr, equal);
2674 }
2675}
2676
2677
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002678Condition LCodeGen::EmitIsObject(Register input,
2679 Register temp1,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002680 Label* is_not_object,
2681 Label* is_object) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002682 __ JumpIfSmi(input, is_not_object);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002684 __ cmp(input, isolate()->factory()->null_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002685 __ j(equal, is_object);
2686
2687 __ mov(temp1, FieldOperand(input, HeapObject::kMapOffset));
2688 // Undetectable objects behave like undefined.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002689 __ test_b(FieldOperand(temp1, Map::kBitFieldOffset),
2690 1 << Map::kIsUndetectable);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002691 __ j(not_zero, is_not_object);
2692
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002693 __ movzx_b(temp1, FieldOperand(temp1, Map::kInstanceTypeOffset));
2694 __ cmp(temp1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002695 __ j(below, is_not_object);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00002696 __ cmp(temp1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002697 return below_equal;
2698}
2699
2700
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002701void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002702 Register reg = ToRegister(instr->value());
2703 Register temp = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002704
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002705 Condition true_cond = EmitIsObject(
2706 reg, temp, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002707
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002708 EmitBranch(instr, true_cond);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002709}
2710
2711
erikcorry0ad885c2011-11-21 13:51:57 +00002712Condition LCodeGen::EmitIsString(Register input,
2713 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002714 Label* is_not_string,
2715 SmiCheck check_needed = INLINE_SMI_CHECK) {
2716 if (check_needed == INLINE_SMI_CHECK) {
2717 __ JumpIfSmi(input, is_not_string);
2718 }
erikcorry0ad885c2011-11-21 13:51:57 +00002719
2720 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2721
2722 return cond;
2723}
2724
2725
2726void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002727 Register reg = ToRegister(instr->value());
2728 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002729
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002730 SmiCheck check_needed =
2731 instr->hydrogen()->value()->IsHeapObject()
2732 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erikcorry0ad885c2011-11-21 13:51:57 +00002733
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002734 Condition true_cond = EmitIsString(
2735 reg, temp, instr->FalseLabel(chunk_), check_needed);
erikcorry0ad885c2011-11-21 13:51:57 +00002736
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002737 EmitBranch(instr, true_cond);
erikcorry0ad885c2011-11-21 13:51:57 +00002738}
2739
2740
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002741void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002742 Operand input = ToOperand(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002743
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002744 __ test(input, Immediate(kSmiTagMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002745 EmitBranch(instr, zero);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002746}
2747
2748
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002749void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002750 Register input = ToRegister(instr->value());
2751 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002752
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002753 if (!instr->hydrogen()->value()->IsHeapObject()) {
2754 STATIC_ASSERT(kSmiTag == 0);
2755 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2756 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002757 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
2758 __ test_b(FieldOperand(temp, Map::kBitFieldOffset),
2759 1 << Map::kIsUndetectable);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002760 EmitBranch(instr, not_zero);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002761}
2762
2763
erikcorry0ad885c2011-11-21 13:51:57 +00002764static Condition ComputeCompareCondition(Token::Value op) {
2765 switch (op) {
2766 case Token::EQ_STRICT:
2767 case Token::EQ:
2768 return equal;
2769 case Token::LT:
2770 return less;
2771 case Token::GT:
2772 return greater;
2773 case Token::LTE:
2774 return less_equal;
2775 case Token::GTE:
2776 return greater_equal;
2777 default:
2778 UNREACHABLE();
2779 return no_condition;
2780 }
2781}
2782
2783
2784void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2785 Token::Value op = instr->op();
erikcorry0ad885c2011-11-21 13:51:57 +00002786
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002787 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002788 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2789
2790 Condition condition = ComputeCompareCondition(op);
2791 __ test(eax, Operand(eax));
2792
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002793 EmitBranch(instr, condition);
erikcorry0ad885c2011-11-21 13:51:57 +00002794}
2795
2796
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002797static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002798 InstanceType from = instr->from();
2799 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002800 if (from == FIRST_TYPE) return to;
2801 ASSERT(from == to || to == LAST_TYPE);
2802 return from;
2803}
2804
2805
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002806static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002807 InstanceType from = instr->from();
2808 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002809 if (from == to) return equal;
2810 if (to == LAST_TYPE) return above_equal;
2811 if (from == FIRST_TYPE) return below_equal;
2812 UNREACHABLE();
2813 return equal;
2814}
2815
2816
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002817void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002818 Register input = ToRegister(instr->value());
2819 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002820
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002821 if (!instr->hydrogen()->value()->IsHeapObject()) {
2822 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2823 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002824
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002825 __ CmpObjectType(input, TestType(instr->hydrogen()), temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002826 EmitBranch(instr, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002827}
2828
2829
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002830void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002831 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002832 Register result = ToRegister(instr->result());
2833
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002834 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002835
2836 __ mov(result, FieldOperand(input, String::kHashFieldOffset));
2837 __ IndexFromHash(result, result);
2838}
2839
2840
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002841void LCodeGen::DoHasCachedArrayIndexAndBranch(
2842 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002843 Register input = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002844
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002845 __ test(FieldOperand(input, String::kHashFieldOffset),
2846 Immediate(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002847 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002848}
2849
2850
2851// Branches to a label or falls through with the answer in the z flag. Trashes
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002852// the temp registers, but not the input.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002853void LCodeGen::EmitClassOfTest(Label* is_true,
2854 Label* is_false,
2855 Handle<String>class_name,
2856 Register input,
2857 Register temp,
2858 Register temp2) {
2859 ASSERT(!input.is(temp));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002860 ASSERT(!input.is(temp2));
2861 ASSERT(!temp.is(temp2));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002862 __ JumpIfSmi(input, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002864 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002865 // Assuming the following assertions, we can use the same compares to test
2866 // for both being a function type and being in the object type range.
2867 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2868 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2869 FIRST_SPEC_OBJECT_TYPE + 1);
2870 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2871 LAST_SPEC_OBJECT_TYPE - 1);
2872 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2873 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2874 __ j(below, is_false);
2875 __ j(equal, is_true);
2876 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2877 __ j(equal, is_true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002878 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002879 // Faster code path to avoid two compares: subtract lower bound from the
2880 // actual type and do a signed compare with the width of the type range.
2881 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002882 __ movzx_b(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002883 __ sub(Operand(temp2), Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002884 __ cmp(Operand(temp2), Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2885 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002886 __ j(above, is_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002887 }
2888
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002889 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002890 // Check if the constructor in the map is a function.
2891 __ mov(temp, FieldOperand(temp, Map::kConstructorOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002892 // Objects with a non-function constructor have class 'Object'.
2893 __ CmpObjectType(temp, JS_FUNCTION_TYPE, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002894 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002895 __ j(not_equal, is_true);
2896 } else {
2897 __ j(not_equal, is_false);
2898 }
2899
2900 // temp now contains the constructor function. Grab the
2901 // instance class name from there.
2902 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2903 __ mov(temp, FieldOperand(temp,
2904 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002905 // The class name we are testing against is internalized since it's a literal.
2906 // The name in the constructor is internalized because of the way the context
2907 // is booted. This routine isn't expected to work for random API-created
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002908 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002909 // syntax. Since both sides are internalized it is sufficient to use an
2910 // identity comparison.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002911 __ cmp(temp, class_name);
2912 // End with the answer in the z flag.
2913}
2914
2915
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002916void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002917 Register input = ToRegister(instr->value());
2918 Register temp = ToRegister(instr->temp());
2919 Register temp2 = ToRegister(instr->temp2());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002920
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002921 Handle<String> class_name = instr->hydrogen()->class_name();
2922
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002923 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2924 class_name, input, temp, temp2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002925
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002926 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002927}
2928
2929
2930void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002931 Register reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002932 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002933 EmitBranch(instr, equal);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002934}
2935
2936
2937void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002938 // Object and function are in fixed registers defined by the stub.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002939 ASSERT(ToRegister(instr->context()).is(esi));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002940 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002941 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002942
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002943 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002944 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002945 __ j(zero, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002946 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002947 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002948 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002950 __ bind(&done);
2951}
2952
2953
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002954void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002955 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002956 public:
2957 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00002958 LInstanceOfKnownGlobal* instr,
2959 const X87Stack& x87_stack)
2960 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002961 virtual void Generate() V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002962 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002963 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002964 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002965 Label* map_check() { return &map_check_; }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002966 private:
2967 LInstanceOfKnownGlobal* instr_;
2968 Label map_check_;
2969 };
2970
2971 DeferredInstanceOfKnownGlobal* deferred;
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00002972 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr, x87_stack_);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002973
2974 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002975 Register object = ToRegister(instr->value());
2976 Register temp = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002977
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002978 // A Smi is not an instance of anything.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002979 __ JumpIfSmi(object, &false_result, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002980
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002981 // This is the inlined call site instanceof cache. The two occurences of the
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002982 // hole value will be patched to the last map/result pair generated by the
2983 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002984 Label cache_miss;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002985 Register map = ToRegister(instr->temp());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002986 __ mov(map, FieldOperand(object, HeapObject::kMapOffset));
2987 __ bind(deferred->map_check()); // Label for calculating code patching.
danno@chromium.org41728482013-06-12 22:31:22 +00002988 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2989 __ cmp(map, Operand::ForCell(cache_cell)); // Patched to cached map.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002990 __ j(not_equal, &cache_miss, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002991 __ mov(eax, factory()->the_hole_value()); // Patched to either true or false.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002992 __ jmp(&done, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002993
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002994 // The inlined call site cache did not match. Check for null and string
2995 // before calling the deferred code.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002996 __ bind(&cache_miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002997 // Null is not an instance of anything.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 __ cmp(object, factory()->null_value());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002999 __ j(equal, &false_result, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003000
3001 // String values are not instances of anything.
3002 Condition is_string = masm_->IsObjectStringType(object, temp, temp);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003003 __ j(is_string, &false_result, Label::kNear);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003004
3005 // Go to the deferred code.
3006 __ jmp(deferred->entry());
3007
3008 __ bind(&false_result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003009 __ mov(ToRegister(instr->result()), factory()->false_value());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003010
3011 // Here result has either true or false. Deferred code also produces true or
3012 // false object.
3013 __ bind(deferred->exit());
3014 __ bind(&done);
3015}
3016
3017
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003018void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
3019 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003020 PushSafepointRegistersScope scope(this);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003021
3022 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
3023 flags = static_cast<InstanceofStub::Flags>(
3024 flags | InstanceofStub::kArgsInRegisters);
3025 flags = static_cast<InstanceofStub::Flags>(
3026 flags | InstanceofStub::kCallSiteInlineCheck);
3027 flags = static_cast<InstanceofStub::Flags>(
3028 flags | InstanceofStub::kReturnTrueFalseObject);
3029 InstanceofStub stub(flags);
3030
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003031 // Get the temp register reserved by the instruction. This needs to be a
3032 // register which is pushed last by PushSafepointRegisters as top of the
3033 // stack is used to pass the offset to the location of the map check to
3034 // the stub.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003035 Register temp = ToRegister(instr->temp());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003036 ASSERT(MacroAssembler::SafepointRegisterStackIndex(temp) == 0);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003037 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003038 static const int kAdditionalDelta = 13;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003039 int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003040 __ mov(temp, Immediate(delta));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003041 __ StoreToSafepointRegisterSlot(temp, temp);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003042 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003043 RelocInfo::CODE_TARGET,
3044 instr,
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003045 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003046 // Get the deoptimization index of the LLazyBailout-environment that
3047 // corresponds to this instruction.
3048 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003049 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
3050
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003051 // Put the result value into the eax slot and restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003052 __ StoreToSafepointRegisterSlot(eax, eax);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003053}
3054
3055
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003056void LCodeGen::DoCmpT(LCmpT* instr) {
3057 Token::Value op = instr->op();
3058
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003059 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003060 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003061
3062 Condition condition = ComputeCompareCondition(op);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003063 Label true_value, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003064 __ test(eax, Operand(eax));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003065 __ j(condition, &true_value, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 __ mov(ToRegister(instr->result()), factory()->false_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003067 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003068 __ bind(&true_value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003069 __ mov(ToRegister(instr->result()), factory()->true_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003070 __ bind(&done);
3071}
3072
3073
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003074void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) {
3075 int extra_value_count = dynamic_frame_alignment ? 2 : 1;
3076
3077 if (instr->has_constant_parameter_count()) {
3078 int parameter_count = ToInteger32(instr->constant_parameter_count());
3079 if (dynamic_frame_alignment && FLAG_debug_code) {
3080 __ cmp(Operand(esp,
3081 (parameter_count + extra_value_count) * kPointerSize),
3082 Immediate(kAlignmentZapValue));
danno@chromium.org59400602013-08-13 17:09:37 +00003083 __ Assert(equal, kExpectedAlignmentMarker);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003084 }
3085 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx);
3086 } else {
3087 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003088 // The argument count parameter is a smi
3089 __ SmiUntag(reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003090 Register return_addr_reg = reg.is(ecx) ? ebx : ecx;
3091 if (dynamic_frame_alignment && FLAG_debug_code) {
3092 ASSERT(extra_value_count == 2);
3093 __ cmp(Operand(esp, reg, times_pointer_size,
3094 extra_value_count * kPointerSize),
3095 Immediate(kAlignmentZapValue));
danno@chromium.org59400602013-08-13 17:09:37 +00003096 __ Assert(equal, kExpectedAlignmentMarker);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003097 }
3098
3099 // emit code to restore stack based on instr->parameter_count()
3100 __ pop(return_addr_reg); // save return address
3101 if (dynamic_frame_alignment) {
3102 __ inc(reg); // 1 more for alignment
3103 }
3104 __ shl(reg, kPointerSizeLog2);
3105 __ add(esp, reg);
3106 __ jmp(return_addr_reg);
3107 }
3108}
3109
3110
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003111void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003112 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003113 // Preserve the return value on the stack and rely on the runtime call
3114 // to return the value in the same register. We're leaving the code
3115 // managed by the register allocator and tearing down the frame, it's
3116 // safe to write to the context register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003117 __ push(eax);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003118 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003119 __ CallRuntime(Runtime::kTraceExit, 1);
3120 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003121 if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(SSE2)) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00003122 RestoreCallerDoubles();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00003123 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003124 if (dynamic_frame_alignment_) {
3125 // Fetch the state of the dynamic frame alignment.
3126 __ mov(edx, Operand(ebp,
3127 JavaScriptFrameConstants::kDynamicAlignmentStateOffset));
3128 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003129 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003130 if (NeedsEagerFrame()) {
3131 __ mov(esp, ebp);
3132 __ pop(ebp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003133 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003134 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003135 if (dynamic_frame_alignment_) {
3136 Label no_padding;
3137 __ cmp(edx, Immediate(kNoAlignmentPadding));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003138 __ j(equal, &no_padding, Label::kNear);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003139
3140 EmitReturn(instr, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003141 __ bind(&no_padding);
3142 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00003143
3144 EmitReturn(instr, false);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003145 if (no_frame_start != -1) {
3146 info()->AddNoFrameRange(no_frame_start, masm_->pc_offset());
3147 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003148}
3149
3150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003151void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003152 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003153 __ mov(result, Operand::ForCell(instr->hydrogen()->cell().handle()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003154 if (instr->hydrogen()->RequiresHoleCheck()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 __ cmp(result, factory()->the_hole_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003156 DeoptimizeIf(equal, instr->environment());
3157 }
3158}
3159
3160
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003161void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
3162 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003163 ASSERT(ToRegister(instr->global_object()).is(edx));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003164 ASSERT(ToRegister(instr->result()).is(eax));
3165
3166 __ mov(ecx, instr->name());
3167 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
3168 RelocInfo::CODE_TARGET_CONTEXT;
3169 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003170 CallCode(ic, mode, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003171}
3172
3173
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003174void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00003175 Register value = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003176 Handle<PropertyCell> cell_handle = instr->hydrogen()->cell().handle();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003177
3178 // If the cell we are storing to contains the hole it could have
3179 // been deleted from the property dictionary. In that case, we need
3180 // to update the property details in the property dictionary to mark
3181 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003182 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.org41728482013-06-12 22:31:22 +00003183 __ cmp(Operand::ForCell(cell_handle), factory()->the_hole_value());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003184 DeoptimizeIf(equal, instr->environment());
3185 }
3186
3187 // Store the value.
danno@chromium.org41728482013-06-12 22:31:22 +00003188 __ mov(Operand::ForCell(cell_handle), value);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003189 // Cells are always rescanned, so no write barrier here.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003190}
3191
3192
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003193void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
3194 ASSERT(ToRegister(instr->context()).is(esi));
3195 ASSERT(ToRegister(instr->global_object()).is(edx));
3196 ASSERT(ToRegister(instr->value()).is(eax));
3197
3198 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003199 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003200 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3201 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003202 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00003203}
3204
3205
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003206void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003207 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003208 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003209 __ mov(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003210
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003211 if (instr->hydrogen()->RequiresHoleCheck()) {
3212 __ cmp(result, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003213 if (instr->hydrogen()->DeoptimizesOnHole()) {
3214 DeoptimizeIf(equal, instr->environment());
3215 } else {
3216 Label is_not_hole;
3217 __ j(not_equal, &is_not_hole, Label::kNear);
3218 __ mov(result, factory()->undefined_value());
3219 __ bind(&is_not_hole);
3220 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003221 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003222}
3223
3224
3225void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
3226 Register context = ToRegister(instr->context());
3227 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003228
3229 Label skip_assignment;
3230
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003231 Operand target = ContextOperand(context, instr->slot_index());
3232 if (instr->hydrogen()->RequiresHoleCheck()) {
3233 __ cmp(target, factory()->the_hole_value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003234 if (instr->hydrogen()->DeoptimizesOnHole()) {
3235 DeoptimizeIf(equal, instr->environment());
3236 } else {
3237 __ j(not_equal, &skip_assignment, Label::kNear);
3238 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003239 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003240
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003241 __ mov(target, value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003242 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003243 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003244 instr->hydrogen()->value()->IsHeapObject()
3245 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003246 Register temp = ToRegister(instr->temp());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003247 int offset = Context::SlotOffset(instr->slot_index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003248 __ RecordWriteContextSlot(context,
3249 offset,
3250 value,
3251 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003252 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003253 EMIT_REMEMBERED_SET,
3254 check_needed);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003255 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00003256
3257 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003258}
3259
3260
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003261void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003262 HObjectAccess access = instr->hydrogen()->access();
3263 int offset = access.offset();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003264
3265 if (access.IsExternalMemory()) {
3266 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003267 MemOperand operand = instr->object()->IsConstantOperand()
3268 ? MemOperand::StaticVariable(ToExternalReference(
3269 LConstantOperand::cast(instr->object())))
3270 : MemOperand(ToRegister(instr->object()), offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003271 __ Load(result, operand, access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003272 return;
3273 }
3274
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003275 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003276 if (FLAG_track_double_fields &&
3277 instr->hydrogen()->representation().IsDouble()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003278 if (CpuFeatures::IsSupported(SSE2)) {
3279 CpuFeatureScope scope(masm(), SSE2);
3280 XMMRegister result = ToDoubleRegister(instr->result());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003281 __ movsd(result, FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00003282 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003283 X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset));
danno@chromium.orgf005df62013-04-30 16:36:45 +00003284 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003285 return;
3286 }
3287
3288 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003289 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003290 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003291 object = result;
3292 }
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003293 __ Load(result, FieldOperand(object, offset), access.representation());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294}
3295
3296
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003297void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
3298 ASSERT(!operand->IsDoubleRegister());
3299 if (operand->IsConstantOperand()) {
3300 Handle<Object> object = ToHandle(LConstantOperand::cast(operand));
rossberg@chromium.org79e79022013-06-03 15:43:46 +00003301 AllowDeferredHandleDereference smi_check;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003302 if (object->IsSmi()) {
3303 __ Push(Handle<Smi>::cast(object));
3304 } else {
3305 __ PushHeapObject(Handle<HeapObject>::cast(object));
3306 }
3307 } else if (operand->IsRegister()) {
3308 __ push(ToRegister(operand));
3309 } else {
3310 __ push(ToOperand(operand));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003311 }
3312}
3313
3314
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003315void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003316 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003317 ASSERT(ToRegister(instr->object()).is(edx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003318 ASSERT(ToRegister(instr->result()).is(eax));
3319
3320 __ mov(ecx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003321 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003322 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003323}
3324
3325
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003326void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
3327 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003328 Register temp = ToRegister(instr->temp());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003329 Register result = ToRegister(instr->result());
3330
3331 // Check that the function really is a function.
3332 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
3333 DeoptimizeIf(not_equal, instr->environment());
3334
3335 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003336 Label non_instance;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003337 __ test_b(FieldOperand(result, Map::kBitFieldOffset),
3338 1 << Map::kHasNonInstancePrototype);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003339 __ j(not_zero, &non_instance, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003340
3341 // Get the prototype or initial map from the function.
3342 __ mov(result,
3343 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
3344
3345 // Check that the function has a prototype or an initial map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 __ cmp(Operand(result), Immediate(factory()->the_hole_value()));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003347 DeoptimizeIf(equal, instr->environment());
3348
3349 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003350 Label done;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003351 __ CmpObjectType(result, MAP_TYPE, temp);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003352 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003353
3354 // Get the prototype from the initial map.
3355 __ mov(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003356 __ jmp(&done, Label::kNear);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00003357
3358 // Non-instance prototype: Fetch prototype from constructor field
3359 // in the function's map.
3360 __ bind(&non_instance);
3361 __ mov(result, FieldOperand(result, Map::kConstructorOffset));
3362
3363 // All done.
3364 __ bind(&done);
3365}
3366
3367
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003368void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3369 Register result = ToRegister(instr->result());
3370 __ LoadRoot(result, instr->index());
3371}
3372
3373
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003374void LCodeGen::DoLoadExternalArrayPointer(
3375 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003376 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003377 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003378 __ mov(result, FieldOperand(input,
3379 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003380}
3381
3382
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003383void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3384 Register arguments = ToRegister(instr->arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003385 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003386 if (instr->length()->IsConstantOperand() &&
3387 instr->index()->IsConstantOperand()) {
3388 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3389 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3390 int index = (const_length - const_index) + 1;
3391 __ mov(result, Operand(arguments, index * kPointerSize));
3392 } else {
3393 Register length = ToRegister(instr->length());
3394 Operand index = ToOperand(instr->index());
3395 // There are two words between the frame pointer and the last argument.
3396 // Subtracting from length accounts for one of them add one more.
3397 __ sub(length, index);
3398 __ mov(result, Operand(arguments, length, times_4, kPointerSize));
3399 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003400}
3401
3402
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003403void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003404 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003405 LOperand* key = instr->key();
3406 if (!key->IsConstantOperand() &&
3407 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
3408 elements_kind)) {
3409 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003410 }
3411 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003412 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003413 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003414 instr->hydrogen()->key()->representation(),
3415 elements_kind,
3416 0,
3417 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003418 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003419 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003420 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003421 XMMRegister result(ToDoubleRegister(instr->result()));
3422 __ movss(result, operand);
3423 __ cvtss2sd(result, result);
3424 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003425 X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003426 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003427 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003428 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003429 CpuFeatureScope scope(masm(), SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003430 __ movsd(ToDoubleRegister(instr->result()), operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003431 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003432 X87Mov(ToX87Register(instr->result()), operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003433 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003434 } else {
3435 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003436 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003437 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003438 __ movsx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003439 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003440 case EXTERNAL_PIXEL_ELEMENTS:
3441 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003442 __ movzx_b(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003443 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003444 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003445 __ movsx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003446 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003447 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003448 __ movzx_w(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003449 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003450 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003451 __ mov(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003452 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003453 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003454 __ mov(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003455 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3456 __ test(result, Operand(result));
3457 DeoptimizeIf(negative, instr->environment());
3458 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003459 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003460 case EXTERNAL_FLOAT_ELEMENTS:
3461 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003462 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003463 case FAST_ELEMENTS:
3464 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003465 case FAST_HOLEY_SMI_ELEMENTS:
3466 case FAST_HOLEY_ELEMENTS:
3467 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003468 case DICTIONARY_ELEMENTS:
3469 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003470 UNREACHABLE();
3471 break;
3472 }
3473 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003474}
3475
3476
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003477void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003478 if (instr->hydrogen()->RequiresHoleCheck()) {
3479 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3480 sizeof(kHoleNanLower32);
3481 Operand hole_check_operand = BuildFastArrayOperand(
3482 instr->elements(), instr->key(),
3483 instr->hydrogen()->key()->representation(),
3484 FAST_DOUBLE_ELEMENTS,
3485 offset,
3486 instr->additional_index());
3487 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32));
3488 DeoptimizeIf(equal, instr->environment());
3489 }
3490
3491 Operand double_load_operand = BuildFastArrayOperand(
3492 instr->elements(),
3493 instr->key(),
3494 instr->hydrogen()->key()->representation(),
3495 FAST_DOUBLE_ELEMENTS,
3496 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3497 instr->additional_index());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003498 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003499 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003500 XMMRegister result = ToDoubleRegister(instr->result());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003501 __ movsd(result, double_load_operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003502 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00003503 X87Mov(ToX87Register(instr->result()), double_load_operand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003504 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003505}
3506
3507
3508void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3509 Register result = ToRegister(instr->result());
3510
3511 // Load the result.
3512 __ mov(result,
3513 BuildFastArrayOperand(instr->elements(),
3514 instr->key(),
3515 instr->hydrogen()->key()->representation(),
3516 FAST_ELEMENTS,
3517 FixedArray::kHeaderSize - kHeapObjectTag,
3518 instr->additional_index()));
3519
3520 // Check for the hole value.
3521 if (instr->hydrogen()->RequiresHoleCheck()) {
3522 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3523 __ test(result, Immediate(kSmiTagMask));
3524 DeoptimizeIf(not_equal, instr->environment());
3525 } else {
3526 __ cmp(result, factory()->the_hole_value());
3527 DeoptimizeIf(equal, instr->environment());
3528 }
3529 }
3530}
3531
3532
3533void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3534 if (instr->is_external()) {
3535 DoLoadKeyedExternalArray(instr);
3536 } else if (instr->hydrogen()->representation().IsDouble()) {
3537 DoLoadKeyedFixedDoubleArray(instr);
3538 } else {
3539 DoLoadKeyedFixedArray(instr);
3540 }
3541}
3542
3543
3544Operand LCodeGen::BuildFastArrayOperand(
3545 LOperand* elements_pointer,
3546 LOperand* key,
3547 Representation key_representation,
3548 ElementsKind elements_kind,
3549 uint32_t offset,
3550 uint32_t additional_index) {
3551 Register elements_pointer_reg = ToRegister(elements_pointer);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003552 int element_shift_size = ElementsKindToShiftSize(elements_kind);
3553 int shift_size = element_shift_size;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003554 if (key->IsConstantOperand()) {
3555 int constant_value = ToInteger32(LConstantOperand::cast(key));
3556 if (constant_value & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003557 Abort(kArrayIndexConstantValueTooBig);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003558 }
3559 return Operand(elements_pointer_reg,
3560 ((constant_value + additional_index) << shift_size)
3561 + offset);
3562 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003563 // Take the tag bit into account while computing the shift size.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003564 if (key_representation.IsSmi() && (shift_size >= 1)) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00003565 shift_size -= kSmiTagSize;
3566 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003567 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3568 return Operand(elements_pointer_reg,
3569 ToRegister(key),
3570 scale_factor,
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003571 offset + (additional_index << element_shift_size));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003572 }
3573}
3574
3575
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003576void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003577 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003578 ASSERT(ToRegister(instr->object()).is(edx));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003579 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003580
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003581 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003582 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003583}
3584
3585
3586void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3587 Register result = ToRegister(instr->result());
3588
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003589 if (instr->hydrogen()->from_inlined()) {
3590 __ lea(result, Operand(esp, -2 * kPointerSize));
3591 } else {
3592 // Check for arguments adapter frame.
3593 Label done, adapted;
3594 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3595 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
3596 __ cmp(Operand(result),
3597 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3598 __ j(equal, &adapted, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003599
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003600 // No arguments adaptor frame.
3601 __ mov(result, Operand(ebp));
3602 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003603
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003604 // Arguments adaptor frame present.
3605 __ bind(&adapted);
3606 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003607
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003608 // Result is the frame pointer for the frame if not adapted and for the real
3609 // frame below the adaptor frame if adapted.
3610 __ bind(&done);
3611 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003612}
3613
3614
3615void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003616 Operand elem = ToOperand(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003617 Register result = ToRegister(instr->result());
3618
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003619 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003620
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003621 // If no arguments adaptor frame the number of arguments is fixed.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003622 __ cmp(ebp, elem);
3623 __ mov(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003624 __ j(equal, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003625
3626 // Arguments adaptor frame present. Get argument length from there.
3627 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3628 __ mov(result, Operand(result,
3629 ArgumentsAdaptorFrameConstants::kLengthOffset));
3630 __ SmiUntag(result);
3631
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003632 // Argument length is in result register.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003633 __ bind(&done);
3634}
3635
3636
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003637void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003638 Register receiver = ToRegister(instr->receiver());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003639 Register function = ToRegister(instr->function());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003640 Register scratch = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003641
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003642 // If the receiver is null or undefined, we have to pass the global
3643 // object as a receiver to normal functions. Values have to be
3644 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003645 Label global_object, receiver_ok;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003646 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003647
3648 // Do not transform the receiver to object for strict mode
3649 // functions.
3650 __ mov(scratch,
3651 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3652 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset),
3653 1 << SharedFunctionInfo::kStrictModeBitWithinByte);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003654 __ j(not_equal, &receiver_ok, dist);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003655
3656 // Do not transform the receiver to object for builtins.
3657 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset),
3658 1 << SharedFunctionInfo::kNativeBitWithinByte);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003659 __ j(not_equal, &receiver_ok, dist);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003660
3661 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003662 __ cmp(receiver, factory()->null_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003663 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 __ cmp(receiver, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003665 __ j(equal, &global_object, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003666
3667 // The receiver should be a JS object.
3668 __ test(receiver, Immediate(kSmiTagMask));
3669 DeoptimizeIf(equal, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003670 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, scratch);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003671 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003672 __ jmp(&receiver_ok, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003673
3674 __ bind(&global_object);
3675 // TODO(kmillikin): We have a hydrogen value for the global object. See
3676 // if it's better to use it than to explicitly fetch it from the context
3677 // here.
3678 __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003679 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003680 __ mov(receiver,
3681 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003682 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003683}
3684
3685
3686void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3687 Register receiver = ToRegister(instr->receiver());
3688 Register function = ToRegister(instr->function());
3689 Register length = ToRegister(instr->length());
3690 Register elements = ToRegister(instr->elements());
3691 ASSERT(receiver.is(eax)); // Used for parameter count.
3692 ASSERT(function.is(edi)); // Required by InvokeFunction.
3693 ASSERT(ToRegister(instr->result()).is(eax));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003694
3695 // Copy the arguments to this function possibly from the
3696 // adaptor frame below it.
3697 const uint32_t kArgumentsLimit = 1 * KB;
3698 __ cmp(length, kArgumentsLimit);
3699 DeoptimizeIf(above, instr->environment());
3700
3701 __ push(receiver);
3702 __ mov(receiver, length);
3703
3704 // Loop through the arguments pushing them onto the execution
3705 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003706 Label invoke, loop;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003707 // length is a small non-negative integer, due to the test above.
3708 __ test(length, Operand(length));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003709 __ j(zero, &invoke, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003710 __ bind(&loop);
3711 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize));
3712 __ dec(length);
3713 __ j(not_zero, &loop);
3714
3715 // Invoke the function.
3716 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003717 ASSERT(instr->HasPointerMap());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00003718 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003719 SafepointGenerator safepoint_generator(
3720 this, pointers, Safepoint::kLazyDeopt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003721 ParameterCount actual(eax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003722 __ InvokeFunction(function, actual, CALL_FUNCTION,
3723 safepoint_generator, CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003724}
3725
3726
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00003727void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
3728 __ int3();
3729}
3730
3731
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003732void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003733 LOperand* argument = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003734 EmitPushTaggedOperand(argument);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003735}
3736
3737
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003738void LCodeGen::DoDrop(LDrop* instr) {
3739 __ Drop(instr->count());
3740}
3741
3742
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003743void LCodeGen::DoThisFunction(LThisFunction* instr) {
3744 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003745 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003746}
3747
3748
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003749void LCodeGen::DoContext(LContext* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003750 Register result = ToRegister(instr->result());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003751 if (info()->IsOptimizing()) {
3752 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
3753 } else {
3754 // If there is no frame, the context must be in esi.
3755 ASSERT(result.is(esi));
3756 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003757}
3758
3759
3760void LCodeGen::DoOuterContext(LOuterContext* instr) {
3761 Register context = ToRegister(instr->context());
3762 Register result = ToRegister(instr->result());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003763 __ mov(result,
3764 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003765}
3766
3767
yangguo@chromium.org56454712012-02-16 15:33:53 +00003768void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003769 ASSERT(ToRegister(instr->context()).is(esi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003770 __ push(esi); // The context is the first argument.
3771 __ push(Immediate(instr->hydrogen()->pairs()));
3772 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags())));
3773 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3774}
3775
3776
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003777void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
3778 Register context = ToRegister(instr->context());
3779 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003780 __ mov(result,
3781 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003782}
3783
3784
3785void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003786 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003787 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003788 __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003789}
3790
3791
3792void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003793 int formal_parameter_count,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003794 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003795 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003796 CallKind call_kind,
3797 EDIState edi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003798 bool dont_adapt_arguments =
3799 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3800 bool can_invoke_directly =
3801 dont_adapt_arguments || formal_parameter_count == arity;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003802
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003803 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003804 if (edi_state == EDI_UNINITIALIZED) {
3805 __ LoadHeapObject(edi, function);
3806 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003807
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003808 // Change context.
3809 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003810
3811 // Set eax to arguments count if adaption is not needed. Assumes that eax
3812 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003813 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003814 __ mov(eax, arity);
3815 }
3816
3817 // Invoke function directly.
3818 __ SetCallKind(ecx, call_kind);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003819 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003820 __ CallSelf();
3821 } else {
3822 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
3823 }
3824 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3825 } else {
3826 // We need to adapt arguments.
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +00003827 LPointerMap* pointers = instr->pointer_map();
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003828 SafepointGenerator generator(
3829 this, pointers, Safepoint::kLazyDeopt);
3830 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003831 ParameterCount expected(formal_parameter_count);
3832 __ InvokeFunction(
3833 function, expected, count, CALL_FUNCTION, generator, call_kind);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003834 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003835}
3836
3837
3838void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3839 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003840 CallKnownFunction(instr->hydrogen()->function(),
3841 instr->hydrogen()->formal_parameter_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00003842 instr->arity(),
3843 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003844 CALL_AS_METHOD,
3845 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003846}
3847
3848
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003849void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003850 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003851 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003852 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003853 DeoptimizeIf(not_equal, instr->environment());
3854
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003855 Label slow, allocated, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003856 Register tmp = input_reg.is(eax) ? ecx : eax;
3857 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx;
3858
3859 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003860 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003861
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003862 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003863 // Check the sign of the argument. If the argument is positive, just
3864 // return it. We do not need to patch the stack since |input| and
3865 // |result| are the same register and |input| will be restored
3866 // unchanged by popping safepoint registers.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003867 __ test(tmp, Immediate(HeapNumber::kSignMask));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003868 __ j(zero, &done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003869
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003871 __ jmp(&allocated, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003872
3873 // Slow case: Call the runtime system to do the number allocation.
3874 __ bind(&slow);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003875 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0,
3876 instr, instr->context());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003877 // Set the pointer to the new heap number in tmp.
3878 if (!tmp.is(eax)) __ mov(tmp, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003879 // Restore input_reg after call to runtime.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003880 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003881
3882 __ bind(&allocated);
3883 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3884 __ and_(tmp2, ~HeapNumber::kSignMask);
3885 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
3886 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
3887 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003888 __ StoreToSafepointRegisterSlot(input_reg, tmp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003889
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003890 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003891}
3892
3893
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003894void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003895 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003896 __ test(input_reg, Operand(input_reg));
3897 Label is_positive;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003898 __ j(not_sign, &is_positive, Label::kNear);
3899 __ neg(input_reg); // Sets flags.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003900 DeoptimizeIf(negative, instr->environment());
3901 __ bind(&is_positive);
3902}
3903
3904
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003905void LCodeGen::DoMathAbs(LMathAbs* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003906 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003907 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003908 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003909 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
3910 LMathAbs* instr,
3911 const X87Stack& x87_stack)
3912 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003913 virtual void Generate() V8_OVERRIDE {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003914 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3915 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003916 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003917 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003918 LMathAbs* instr_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003919 };
3920
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003921 ASSERT(instr->value()->Equals(instr->result()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003922 Representation r = instr->hydrogen()->value()->representation();
3923
ulan@chromium.org750145a2013-03-07 15:14:13 +00003924 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003925 if (r.IsDouble()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003926 XMMRegister scratch = double_scratch0();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003927 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00003928 __ xorps(scratch, scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003929 __ subsd(scratch, input_reg);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00003930 __ andps(input_reg, scratch);
danno@chromium.org59400602013-08-13 17:09:37 +00003931 } else if (r.IsSmiOrInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003932 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003933 } else { // Tagged case.
3934 DeferredMathAbsTaggedHeapNumber* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003935 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr, x87_stack_);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003936 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003937 // Smi check.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003938 __ JumpIfNotSmi(input_reg, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003939 EmitIntegerMathAbs(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003940 __ bind(deferred->exit());
3941 }
3942}
3943
3944
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003945void LCodeGen::DoMathFloor(LMathFloor* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003946 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003947 XMMRegister xmm_scratch = double_scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003948 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00003949 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003950
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003951 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003952 CpuFeatureScope scope(masm(), SSE4_1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003953 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3954 // Deoptimize on negative zero.
3955 Label non_zero;
3956 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3957 __ ucomisd(input_reg, xmm_scratch);
3958 __ j(not_equal, &non_zero, Label::kNear);
3959 __ movmskpd(output_reg, input_reg);
3960 __ test(output_reg, Immediate(1));
3961 DeoptimizeIf(not_zero, instr->environment());
3962 __ bind(&non_zero);
3963 }
3964 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3965 __ cvttsd2si(output_reg, Operand(xmm_scratch));
3966 // Overflow is signalled with minint.
3967 __ cmp(output_reg, 0x80000000u);
3968 DeoptimizeIf(equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003969 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003970 Label negative_sign, done;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003971 // Deoptimize on unordered.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003972 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3973 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003974 DeoptimizeIf(parity_even, instr->environment());
3975 __ j(below, &negative_sign, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003976
3977 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3978 // Check for negative zero.
3979 Label positive_sign;
3980 __ j(above, &positive_sign, Label::kNear);
3981 __ movmskpd(output_reg, input_reg);
3982 __ test(output_reg, Immediate(1));
3983 DeoptimizeIf(not_zero, instr->environment());
3984 __ Set(output_reg, Immediate(0));
3985 __ jmp(&done, Label::kNear);
3986 __ bind(&positive_sign);
3987 }
3988
3989 // Use truncating instruction (OK because input is positive).
3990 __ cvttsd2si(output_reg, Operand(input_reg));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003991 // Overflow is signalled with minint.
3992 __ cmp(output_reg, 0x80000000u);
3993 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003994 __ jmp(&done, Label::kNear);
3995
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003996 // Non-zero negative reaches here.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003997 __ bind(&negative_sign);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003998 // Truncate, then compare and compensate.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003999 __ cvttsd2si(output_reg, Operand(input_reg));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004000 __ Cvtsi2sd(xmm_scratch, output_reg);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00004001 __ ucomisd(input_reg, xmm_scratch);
4002 __ j(equal, &done, Label::kNear);
4003 __ sub(output_reg, Immediate(1));
4004 DeoptimizeIf(overflow, instr->environment());
4005
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004006 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004007 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004008}
4009
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00004010
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004011void LCodeGen::DoMathRound(LMathRound* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004012 CpuFeatureScope scope(masm(), SSE2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004013 Register output_reg = ToRegister(instr->result());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004014 XMMRegister input_reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004015 XMMRegister xmm_scratch = double_scratch0();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004016 XMMRegister input_temp = ToDoubleRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004017 ExternalReference one_half = ExternalReference::address_of_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004018 ExternalReference minus_one_half =
4019 ExternalReference::address_of_minus_one_half();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004020
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004021 Label done, round_to_zero, below_one_half, do_not_compensate;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004022 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
4023
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004024 __ movsd(xmm_scratch, Operand::StaticVariable(one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004025 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004026 __ j(above, &below_one_half, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004027
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004028 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
4029 __ addsd(xmm_scratch, input_reg);
4030 __ cvttsd2si(output_reg, Operand(xmm_scratch));
4031 // Overflow is signalled with minint.
4032 __ cmp(output_reg, 0x80000000u);
4033 __ RecordComment("D2I conversion overflow");
4034 DeoptimizeIf(equal, instr->environment());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004035 __ jmp(&done, dist);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004036
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004037 __ bind(&below_one_half);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004038 __ movsd(xmm_scratch, Operand::StaticVariable(minus_one_half));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004039 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004040 __ j(below_equal, &round_to_zero, Label::kNear);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004041
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004042 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
4043 // compare and compensate.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004044 __ movaps(input_temp, input_reg); // Do not alter input_reg.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004045 __ subsd(input_temp, xmm_scratch);
4046 __ cvttsd2si(output_reg, Operand(input_temp));
4047 // Catch minint due to overflow, and to prevent overflow when compensating.
4048 __ cmp(output_reg, 0x80000000u);
4049 __ RecordComment("D2I conversion overflow");
4050 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004051
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004052 __ Cvtsi2sd(xmm_scratch, output_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004053 __ ucomisd(xmm_scratch, input_temp);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004054 __ j(equal, &done, dist);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004055 __ sub(output_reg, Immediate(1));
4056 // No overflow because we already ruled out minint.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004057 __ jmp(&done, dist);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004058
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004059 __ bind(&round_to_zero);
4060 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
4061 // we can ignore the difference between a result of -0 and +0.
4062 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4063 // If the sign is positive, we return +0.
4064 __ movmskpd(output_reg, input_reg);
4065 __ test(output_reg, Immediate(1));
4066 __ RecordComment("Minus zero");
4067 DeoptimizeIf(not_zero, instr->environment());
danno@chromium.org160a7b02011-04-18 15:51:38 +00004068 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004069 __ Set(output_reg, Immediate(0));
4070 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004071}
4072
4073
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004074void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004075 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004076 XMMRegister input_reg = ToDoubleRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004077 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
4078 __ sqrtsd(input_reg, input_reg);
4079}
4080
4081
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004082void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004083 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004084 XMMRegister xmm_scratch = double_scratch0();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004085 XMMRegister input_reg = ToDoubleRegister(instr->value());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004086 Register scratch = ToRegister(instr->temp());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004087 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004088
4089 // Note that according to ECMA-262 15.8.2.13:
4090 // Math.pow(-Infinity, 0.5) == Infinity
4091 // Math.sqrt(-Infinity) == NaN
4092 Label done, sqrt;
4093 // Check base for -Infinity. According to IEEE-754, single-precision
4094 // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
4095 __ mov(scratch, 0xFF800000);
4096 __ movd(xmm_scratch, scratch);
4097 __ cvtss2sd(xmm_scratch, xmm_scratch);
4098 __ ucomisd(input_reg, xmm_scratch);
4099 // Comparing -Infinity with NaN results in "unordered", which sets the
4100 // zero flag as if both were equal. However, it also sets the carry flag.
4101 __ j(not_equal, &sqrt, Label::kNear);
4102 __ j(carry, &sqrt, Label::kNear);
4103 // If input is -Infinity, return Infinity.
4104 __ xorps(input_reg, input_reg);
4105 __ subsd(input_reg, xmm_scratch);
4106 __ jmp(&done, Label::kNear);
4107
4108 // Square root.
4109 __ bind(&sqrt);
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004110 __ xorps(xmm_scratch, xmm_scratch);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004111 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004112 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004113 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004114}
4115
4116
4117void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004118 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004119 // Having marked this as a call, we can use any registers.
4120 // Just make sure that the input/output registers are the expected ones.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004121 ASSERT(!instr->right()->IsDoubleRegister() ||
4122 ToDoubleRegister(instr->right()).is(xmm1));
4123 ASSERT(!instr->right()->IsRegister() ||
4124 ToRegister(instr->right()).is(eax));
4125 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004126 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004127
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004128 if (exponent_type.IsSmi()) {
4129 MathPowStub stub(MathPowStub::TAGGED);
4130 __ CallStub(&stub);
4131 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004132 Label no_deopt;
4133 __ JumpIfSmi(eax, &no_deopt);
4134 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004135 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004136 __ bind(&no_deopt);
4137 MathPowStub stub(MathPowStub::TAGGED);
4138 __ CallStub(&stub);
4139 } else if (exponent_type.IsInteger32()) {
4140 MathPowStub stub(MathPowStub::INTEGER);
4141 __ CallStub(&stub);
4142 } else {
4143 ASSERT(exponent_type.IsDouble());
4144 MathPowStub stub(MathPowStub::DOUBLE);
4145 __ CallStub(&stub);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004146 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004147}
4148
4149
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004150void LCodeGen::DoMathLog(LMathLog* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004151 CpuFeatureScope scope(masm(), SSE2);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004152 ASSERT(instr->value()->Equals(instr->result()));
4153 XMMRegister input_reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004154 XMMRegister xmm_scratch = double_scratch0();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004155 Label positive, done, zero;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004156 __ xorps(xmm_scratch, xmm_scratch);
4157 __ ucomisd(input_reg, xmm_scratch);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004158 __ j(above, &positive, Label::kNear);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00004159 __ j(not_carry, &zero, Label::kNear);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004160 ExternalReference nan =
4161 ExternalReference::address_of_canonical_non_hole_nan();
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004162 __ movsd(input_reg, Operand::StaticVariable(nan));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004163 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004164 __ bind(&zero);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004165 ExternalReference ninf =
4166 ExternalReference::address_of_negative_infinity();
4167 __ movsd(input_reg, Operand::StaticVariable(ninf));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004168 __ jmp(&done, Label::kNear);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004169 __ bind(&positive);
4170 __ fldln2();
4171 __ sub(Operand(esp), Immediate(kDoubleSize));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004172 __ movsd(Operand(esp, 0), input_reg);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004173 __ fld_d(Operand(esp, 0));
4174 __ fyl2x();
4175 __ fstp_d(Operand(esp, 0));
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004176 __ movsd(input_reg, Operand(esp, 0));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004177 __ add(Operand(esp), Immediate(kDoubleSize));
4178 __ bind(&done);
whesse@chromium.org023421e2010-12-21 12:19:12 +00004179}
4180
4181
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004182void LCodeGen::DoMathExp(LMathExp* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004183 CpuFeatureScope scope(masm(), SSE2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004184 XMMRegister input = ToDoubleRegister(instr->value());
4185 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004186 XMMRegister temp0 = double_scratch0();
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004187 Register temp1 = ToRegister(instr->temp1());
4188 Register temp2 = ToRegister(instr->temp2());
4189
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004190 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004191}
4192
4193
danno@chromium.org160a7b02011-04-18 15:51:38 +00004194void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
4195 ASSERT(ToRegister(instr->context()).is(esi));
4196 ASSERT(ToRegister(instr->function()).is(edi));
4197 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004198
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004199 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
4200 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004201 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004202 SafepointGenerator generator(
4203 this, pointers, Safepoint::kLazyDeopt);
4204 ParameterCount count(instr->arity());
4205 __ InvokeFunction(edi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
4206 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004207 CallKnownFunction(known_function,
4208 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004209 instr->arity(),
4210 instr,
4211 CALL_AS_METHOD,
4212 EDI_CONTAINS_TARGET);
4213 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004214}
4215
4216
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004217void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004218 ASSERT(ToRegister(instr->context()).is(esi));
4219 ASSERT(ToRegister(instr->key()).is(ecx));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004220 ASSERT(ToRegister(instr->result()).is(eax));
4221
4222 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00004223 Handle<Code> ic =
4224 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004225 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004226}
4227
4228
4229void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004230 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004231 ASSERT(ToRegister(instr->result()).is(eax));
4232
4233 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004234 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
4235 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004236 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004237 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004238 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004239}
4240
4241
4242void LCodeGen::DoCallFunction(LCallFunction* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004243 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00004244 ASSERT(ToRegister(instr->function()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004245 ASSERT(ToRegister(instr->result()).is(eax));
4246
4247 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004248 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00004249 if (instr->hydrogen()->IsTailCall()) {
4250 if (NeedsEagerFrame()) __ leave();
4251 __ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
4252 } else {
4253 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4254 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004255}
4256
4257
4258void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004259 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004260 ASSERT(ToRegister(instr->result()).is(eax));
4261
4262 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00004263 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4264 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004265 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004266 __ mov(ecx, instr->name());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004267 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004268}
4269
4270
4271void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4272 ASSERT(ToRegister(instr->result()).is(eax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004273 CallKnownFunction(instr->hydrogen()->target(),
4274 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004275 instr->arity(),
4276 instr,
4277 CALL_AS_FUNCTION,
4278 EDI_UNINITIALIZED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004279}
4280
4281
4282void LCodeGen::DoCallNew(LCallNew* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004283 ASSERT(ToRegister(instr->context()).is(esi));
4284 ASSERT(ToRegister(instr->constructor()).is(edi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004285 ASSERT(ToRegister(instr->result()).is(eax));
4286
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004287 // No cell in ebx for construct type feedback in optimized code
4288 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
4289 __ mov(ebx, Immediate(undefined_value));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004290 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004291 __ Set(eax, Immediate(instr->arity()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004292 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004293}
4294
4295
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004296void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4297 ASSERT(ToRegister(instr->context()).is(esi));
4298 ASSERT(ToRegister(instr->constructor()).is(edi));
4299 ASSERT(ToRegister(instr->result()).is(eax));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004300
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004301 __ Set(eax, Immediate(instr->arity()));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004302 __ mov(ebx, instr->hydrogen()->property_cell());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004303 ElementsKind kind = instr->hydrogen()->elements_kind();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004304 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00004305 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004306 ? DISABLE_ALLOCATION_SITES
4307 : DONT_OVERRIDE;
4308 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004309
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004310 if (instr->arity() == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004311 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004312 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4313 } else if (instr->arity() == 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00004314 Label done;
4315 if (IsFastPackedElementsKind(kind)) {
4316 Label packed_case;
4317 // We might need a change here
4318 // look at the first argument
4319 __ mov(ecx, Operand(esp, 0));
4320 __ test(ecx, ecx);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004321 __ j(zero, &packed_case, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00004322
4323 ElementsKind holey_kind = GetHoleyElementsKind(kind);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004324 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
4325 override_mode);
danno@chromium.org41728482013-06-12 22:31:22 +00004326 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004327 __ jmp(&done, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00004328 __ bind(&packed_case);
4329 }
4330
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004331 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004332 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.org41728482013-06-12 22:31:22 +00004333 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004334 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004335 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004336 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4337 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004338}
4339
4340
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004341void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004342 ASSERT(ToRegister(instr->context()).is(esi));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004343 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004344}
4345
4346
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004347void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
4348 Register function = ToRegister(instr->function());
4349 Register code_object = ToRegister(instr->code_object());
4350 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
4351 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
4352}
4353
4354
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004355void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4356 Register result = ToRegister(instr->result());
4357 Register base = ToRegister(instr->base_object());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004358 if (instr->offset()->IsConstantOperand()) {
4359 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
4360 __ lea(result, Operand(base, ToInteger32(offset)));
4361 } else {
4362 Register offset = ToRegister(instr->offset());
4363 __ lea(result, Operand(base, offset, times_1, 0));
4364 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00004365}
4366
4367
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004368void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004369 Representation representation = instr->representation();
4370
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004371 HObjectAccess access = instr->hydrogen()->access();
4372 int offset = access.offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004373
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004374 if (access.IsExternalMemory()) {
4375 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4376 MemOperand operand = instr->object()->IsConstantOperand()
4377 ? MemOperand::StaticVariable(
4378 ToExternalReference(LConstantOperand::cast(instr->object())))
4379 : MemOperand(ToRegister(instr->object()), offset);
4380 if (instr->value()->IsConstantOperand()) {
4381 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004382 __ mov(operand, Immediate(ToInteger32(operand_value)));
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004383 } else {
4384 Register value = ToRegister(instr->value());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004385 __ Store(value, operand, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004386 }
4387 return;
4388 }
4389
4390 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004391 Handle<Map> transition = instr->transition();
4392
danno@chromium.orgf005df62013-04-30 16:36:45 +00004393 if (FLAG_track_fields && representation.IsSmi()) {
4394 if (instr->value()->IsConstantOperand()) {
4395 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004396 if (!IsSmi(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004397 DeoptimizeIf(no_condition, instr->environment());
4398 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00004399 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004400 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
4401 if (instr->value()->IsConstantOperand()) {
4402 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4403 if (IsInteger32(operand_value)) {
4404 DeoptimizeIf(no_condition, instr->environment());
4405 }
4406 } else {
4407 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
4408 Register value = ToRegister(instr->value());
4409 __ test(value, Immediate(kSmiTagMask));
4410 DeoptimizeIf(zero, instr->environment());
4411 }
4412 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004413 } else if (FLAG_track_double_fields && representation.IsDouble()) {
4414 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004415 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004416 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4417 if (CpuFeatures::IsSupported(SSE2)) {
4418 CpuFeatureScope scope(masm(), SSE2);
4419 XMMRegister value = ToDoubleRegister(instr->value());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004420 __ movsd(FieldOperand(object, offset), value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004421 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00004422 X87Register value = ToX87Register(instr->value());
4423 X87Mov(FieldOperand(object, offset), value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004424 }
4425 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00004426 }
4427
danno@chromium.orgf005df62013-04-30 16:36:45 +00004428 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00004429 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004430 __ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004431 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004432 Register temp = ToRegister(instr->temp());
4433 Register temp_map = ToRegister(instr->temp_map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004434 __ mov(temp_map, transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004435 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
4436 // Update the write barrier for the map field.
4437 __ RecordWriteField(object,
4438 HeapObject::kMapOffset,
4439 temp_map,
4440 temp,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004441 GetSaveFPRegsMode(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004442 OMIT_REMEMBERED_SET,
4443 OMIT_SMI_CHECK);
4444 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004445 }
4446
4447 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004448 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004449 instr->hydrogen()->value()->IsHeapObject()
4450 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004451
4452 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004453 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004454 write_register = ToRegister(instr->temp());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004455 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004456 }
4457
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004458 MemOperand operand = FieldOperand(write_register, offset);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004459 if (instr->value()->IsConstantOperand()) {
4460 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004461 if (operand_value->IsRegister()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004462 Register value = ToRegister(operand_value);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004463 __ Store(value, operand, representation);
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004464 } else if (representation.IsInteger32()) {
4465 Immediate immediate = ToImmediate(operand_value, representation);
4466 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4467 __ mov(operand, immediate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004468 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004469 Handle<Object> handle_value = ToHandle(operand_value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004470 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004471 __ mov(operand, handle_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004472 }
4473 } else {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004474 Register value = ToRegister(instr->value());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004475 __ Store(value, operand, representation);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004476 }
4477
4478 if (instr->hydrogen()->NeedsWriteBarrier()) {
4479 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004480 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004481 // Update the write barrier for the object for in-object properties.
4482 __ RecordWriteField(write_register,
4483 offset,
4484 value,
4485 temp,
4486 GetSaveFPRegsMode(),
4487 EMIT_REMEMBERED_SET,
4488 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004489 }
4490}
4491
4492
4493void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004494 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004495 ASSERT(ToRegister(instr->object()).is(edx));
4496 ASSERT(ToRegister(instr->value()).is(eax));
4497
4498 __ mov(ecx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004499 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004500 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4501 : isolate()->builtins()->StoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004502 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004503}
4504
4505
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004506void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
4507 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4508 Label done;
4509 __ j(NegateCondition(cc), &done, Label::kNear);
4510 __ int3();
4511 __ bind(&done);
4512 } else {
4513 DeoptimizeIf(cc, check->environment());
4514 }
4515}
4516
4517
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004518void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004519 if (instr->hydrogen()->skip_check() && !FLAG_debug_code) return;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004520
danno@chromium.orgb6451162011-08-17 14:33:23 +00004521 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004522 Immediate immediate =
4523 ToImmediate(LConstantOperand::cast(instr->index()),
4524 instr->hydrogen()->length()->representation());
4525 __ cmp(ToOperand(instr->length()), immediate);
4526 Condition condition =
4527 instr->hydrogen()->allow_equality() ? below : below_equal;
4528 ApplyCheckIf(condition, instr);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004529 } else {
4530 __ cmp(ToRegister(instr->index()), ToOperand(instr->length()));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004531 Condition condition =
4532 instr->hydrogen()->allow_equality() ? above : above_equal;
4533 ApplyCheckIf(condition, instr);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004534 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004535}
4536
4537
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004538void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004539 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004540 LOperand* key = instr->key();
4541 if (!key->IsConstantOperand() &&
4542 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(),
4543 elements_kind)) {
4544 __ SmiUntag(ToRegister(key));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004545 }
4546 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004547 instr->elements(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004548 key,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004549 instr->hydrogen()->key()->representation(),
4550 elements_kind,
4551 0,
4552 instr->additional_index()));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004553 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004554 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4555 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004556 XMMRegister xmm_scratch = double_scratch0();
4557 __ cvtsd2ss(xmm_scratch, ToDoubleRegister(instr->value()));
4558 __ movss(operand, xmm_scratch);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004559 } else {
4560 __ fld(0);
4561 __ fstp_s(operand);
4562 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004563 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004564 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4565 CpuFeatureScope scope(masm(), SSE2);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004566 __ movsd(operand, ToDoubleRegister(instr->value()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004567 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00004568 X87Mov(operand, ToX87Register(instr->value()));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004569 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004570 } else {
4571 Register value = ToRegister(instr->value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004572 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004573 case EXTERNAL_PIXEL_ELEMENTS:
4574 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4575 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004576 __ mov_b(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004577 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004578 case EXTERNAL_SHORT_ELEMENTS:
4579 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004580 __ mov_w(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004581 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004582 case EXTERNAL_INT_ELEMENTS:
4583 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004584 __ mov(operand, value);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004585 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004586 case EXTERNAL_FLOAT_ELEMENTS:
4587 case EXTERNAL_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004588 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004589 case FAST_ELEMENTS:
4590 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004591 case FAST_HOLEY_SMI_ELEMENTS:
4592 case FAST_HOLEY_ELEMENTS:
4593 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004594 case DICTIONARY_ELEMENTS:
4595 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004596 UNREACHABLE();
4597 break;
4598 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004599 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004600}
4601
4602
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004603void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004604 ExternalReference canonical_nan_reference =
4605 ExternalReference::address_of_canonical_non_hole_nan();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004606 Operand double_store_operand = BuildFastArrayOperand(
4607 instr->elements(),
4608 instr->key(),
4609 instr->hydrogen()->key()->representation(),
4610 FAST_DOUBLE_ELEMENTS,
4611 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4612 instr->additional_index());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004613
4614 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
4615 CpuFeatureScope scope(masm(), SSE2);
4616 XMMRegister value = ToDoubleRegister(instr->value());
4617
4618 if (instr->NeedsCanonicalization()) {
4619 Label have_value;
4620
4621 __ ucomisd(value, value);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004622 __ j(parity_odd, &have_value, Label::kNear); // NaN.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004623
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004624 __ movsd(value, Operand::StaticVariable(canonical_nan_reference));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004625 __ bind(&have_value);
4626 }
4627
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00004628 __ movsd(double_store_operand, value);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004629 } else {
4630 // Can't use SSE2 in the serializer
4631 if (instr->hydrogen()->IsConstantHoleStore()) {
4632 // This means we should store the (double) hole. No floating point
4633 // registers required.
4634 double nan_double = FixedDoubleArray::hole_nan_as_double();
4635 uint64_t int_val = BitCast<uint64_t, double>(nan_double);
4636 int32_t lower = static_cast<int32_t>(int_val);
4637 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
4638
4639 __ mov(double_store_operand, Immediate(lower));
4640 Operand double_store_operand2 = BuildFastArrayOperand(
4641 instr->elements(),
4642 instr->key(),
4643 instr->hydrogen()->key()->representation(),
4644 FAST_DOUBLE_ELEMENTS,
4645 FixedDoubleArray::kHeaderSize - kHeapObjectTag + kPointerSize,
4646 instr->additional_index());
4647 __ mov(double_store_operand2, Immediate(upper));
4648 } else {
4649 Label no_special_nan_handling;
danno@chromium.org169691d2013-07-15 08:01:13 +00004650 X87Register value = ToX87Register(instr->value());
4651 X87Fxch(value);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004652
4653 if (instr->NeedsCanonicalization()) {
4654 __ fld(0);
4655 __ fld(0);
4656 __ FCmp();
4657
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004658 __ j(parity_odd, &no_special_nan_handling, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004659 __ sub(esp, Immediate(kDoubleSize));
4660 __ fst_d(MemOperand(esp, 0));
4661 __ cmp(MemOperand(esp, sizeof(kHoleNanLower32)),
4662 Immediate(kHoleNanUpper32));
4663 __ add(esp, Immediate(kDoubleSize));
4664 Label canonicalize;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004665 __ j(not_equal, &canonicalize, Label::kNear);
4666 __ jmp(&no_special_nan_handling, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004667 __ bind(&canonicalize);
4668 __ fstp(0);
4669 __ fld_d(Operand::StaticVariable(canonical_nan_reference));
4670 }
4671
4672 __ bind(&no_special_nan_handling);
4673 __ fst_d(double_store_operand);
4674 }
4675 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004676}
4677
4678
4679void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004680 Register elements = ToRegister(instr->elements());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004681 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
4682
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004683 Operand operand = BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004684 instr->elements(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004685 instr->key(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004686 instr->hydrogen()->key()->representation(),
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004687 FAST_ELEMENTS,
4688 FixedArray::kHeaderSize - kHeapObjectTag,
4689 instr->additional_index());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004690 if (instr->value()->IsRegister()) {
4691 __ mov(operand, ToRegister(instr->value()));
4692 } else {
4693 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004694 if (IsSmi(operand_value)) {
4695 Immediate immediate = ToImmediate(operand_value, Representation::Smi());
4696 __ mov(operand, immediate);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004697 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004698 ASSERT(!IsInteger32(operand_value));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004699 Handle<Object> handle_value = ToHandle(operand_value);
4700 __ mov(operand, handle_value);
4701 }
4702 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004703
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004704 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004705 ASSERT(instr->value()->IsRegister());
4706 Register value = ToRegister(instr->value());
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004707 ASSERT(!instr->key()->IsConstantOperand());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004708 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004709 instr->hydrogen()->value()->IsHeapObject()
4710 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004711 // Compute address of modified element and store it into key register.
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004712 __ lea(key, operand);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004713 __ RecordWrite(elements,
4714 key,
4715 value,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004716 GetSaveFPRegsMode(),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004717 EMIT_REMEMBERED_SET,
4718 check_needed);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004719 }
4720}
4721
4722
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004723void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4724 // By cases...external, fast-double, fast
4725 if (instr->is_external()) {
4726 DoStoreKeyedExternalArray(instr);
4727 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4728 DoStoreKeyedFixedDoubleArray(instr);
4729 } else {
4730 DoStoreKeyedFixedArray(instr);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004731 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004732}
4733
4734
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004735void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004736 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004737 ASSERT(ToRegister(instr->object()).is(edx));
4738 ASSERT(ToRegister(instr->key()).is(ecx));
4739 ASSERT(ToRegister(instr->value()).is(eax));
4740
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004741 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004742 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4743 : isolate()->builtins()->KeyedStoreIC_Initialize();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004744 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004745}
4746
4747
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004748void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4749 Register object = ToRegister(instr->object());
4750 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004751 Label no_memento_found;
4752 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004753 DeoptimizeIf(equal, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004754 __ bind(&no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004755}
4756
4757
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004758void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4759 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004760
4761 Handle<Map> from_map = instr->original_map();
4762 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004763 ElementsKind from_kind = instr->from_kind();
4764 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004765
4766 Label not_applicable;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004767 bool is_simple_map_transition =
4768 IsSimpleMapChangeTransition(from_kind, to_kind);
4769 Label::Distance branch_distance =
4770 is_simple_map_transition ? Label::kNear : Label::kFar;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004771 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004772 __ j(not_equal, &not_applicable, branch_distance);
4773 if (is_simple_map_transition) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004774 Register new_map_reg = ToRegister(instr->new_map_temp());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004775 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004776 Immediate(to_map));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004777 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004778 ASSERT_NE(instr->temp(), NULL);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004779 __ RecordWriteForMap(object_reg, to_map, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004780 ToRegister(instr->temp()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004781 kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004782 } else {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00004783 ASSERT(ToRegister(instr->context()).is(esi));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004784 PushSafepointRegistersScope scope(this);
4785 if (!object_reg.is(eax)) {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00004786 __ mov(eax, object_reg);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004787 }
4788 __ mov(ebx, to_map);
4789 TransitionElementsKindStub stub(from_kind, to_kind);
4790 __ CallStub(&stub);
4791 RecordSafepointWithRegisters(
4792 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004793 }
4794 __ bind(&not_applicable);
4795}
4796
4797
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004798void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004799 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004800 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004801 DeferredStringCharCodeAt(LCodeGen* codegen,
4802 LStringCharCodeAt* instr,
4803 const X87Stack& x87_stack)
4804 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004805 virtual void Generate() V8_OVERRIDE {
4806 codegen()->DoDeferredStringCharCodeAt(instr_);
4807 }
4808 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004809 private:
4810 LStringCharCodeAt* instr_;
4811 };
4812
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004813 DeferredStringCharCodeAt* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004814 new(zone()) DeferredStringCharCodeAt(this, instr, x87_stack_);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004815
erikcorry0ad885c2011-11-21 13:51:57 +00004816 StringCharLoadGenerator::Generate(masm(),
4817 factory(),
4818 ToRegister(instr->string()),
4819 ToRegister(instr->index()),
4820 ToRegister(instr->result()),
4821 deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004822 __ bind(deferred->exit());
4823}
4824
4825
4826void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4827 Register string = ToRegister(instr->string());
4828 Register result = ToRegister(instr->result());
4829
4830 // TODO(3095996): Get rid of this. For now, we need to make the
4831 // result register contain a valid pointer because it is already
4832 // contained in the register pointer map.
4833 __ Set(result, Immediate(0));
4834
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004835 PushSafepointRegistersScope scope(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004836 __ push(string);
4837 // Push the index as a smi. This is safe because of the checks in
4838 // DoStringCharCodeAt above.
4839 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4840 if (instr->index()->IsConstantOperand()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004841 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->index()),
4842 Representation::Smi());
4843 __ push(immediate);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004844 } else {
4845 Register index = ToRegister(instr->index());
4846 __ SmiTag(index);
4847 __ push(index);
4848 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004849 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2,
4850 instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004851 __ AssertSmi(eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004852 __ SmiUntag(eax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004853 __ StoreToSafepointRegisterSlot(result, eax);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004854}
4855
4856
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004857void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004858 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004859 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004860 DeferredStringCharFromCode(LCodeGen* codegen,
4861 LStringCharFromCode* instr,
4862 const X87Stack& x87_stack)
4863 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004864 virtual void Generate() V8_OVERRIDE {
4865 codegen()->DoDeferredStringCharFromCode(instr_);
4866 }
4867 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004868 private:
4869 LStringCharFromCode* instr_;
4870 };
4871
4872 DeferredStringCharFromCode* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004873 new(zone()) DeferredStringCharFromCode(this, instr, x87_stack_);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004874
4875 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4876 Register char_code = ToRegister(instr->char_code());
4877 Register result = ToRegister(instr->result());
4878 ASSERT(!char_code.is(result));
4879
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004880 __ cmp(char_code, String::kMaxOneByteCharCode);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004881 __ j(above, deferred->entry());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004882 __ Set(result, Immediate(factory()->single_character_string_cache()));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004883 __ mov(result, FieldOperand(result,
4884 char_code, times_pointer_size,
4885 FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004886 __ cmp(result, factory()->undefined_value());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004887 __ j(equal, deferred->entry());
4888 __ bind(deferred->exit());
4889}
4890
4891
4892void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4893 Register char_code = ToRegister(instr->char_code());
4894 Register result = ToRegister(instr->result());
4895
4896 // TODO(3095996): Get rid of this. For now, we need to make the
4897 // result register contain a valid pointer because it is already
4898 // contained in the register pointer map.
4899 __ Set(result, Immediate(0));
4900
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004901 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004902 __ SmiTag(char_code);
4903 __ push(char_code);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00004904 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004905 __ StoreToSafepointRegisterSlot(result, eax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004906}
4907
4908
danno@chromium.org160a7b02011-04-18 15:51:38 +00004909void LCodeGen::DoStringAdd(LStringAdd* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004910 ASSERT(ToRegister(instr->context()).is(esi));
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004911 if (FLAG_new_string_add) {
4912 ASSERT(ToRegister(instr->left()).is(edx));
4913 ASSERT(ToRegister(instr->right()).is(eax));
4914 NewStringAddStub stub(instr->hydrogen()->flags(),
ulan@chromium.org0f13e742014-01-03 15:51:11 +00004915 instr->hydrogen()->pretenure_flag());
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004916 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4917 } else {
4918 EmitPushTaggedOperand(instr->left());
4919 EmitPushTaggedOperand(instr->right());
4920 StringAddStub stub(instr->hydrogen()->flags());
4921 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4922 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004923}
4924
4925
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004926void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004927 LOperand* input = instr->value();
4928 LOperand* output = instr->result();
4929 ASSERT(input->IsRegister() || input->IsStackSlot());
4930 ASSERT(output->IsDoubleRegister());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004931 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004932 CpuFeatureScope scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004933 __ Cvtsi2sd(ToDoubleRegister(output), ToOperand(input));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004934 } else if (input->IsRegister()) {
4935 Register input_reg = ToRegister(input);
4936 __ push(input_reg);
4937 X87Mov(ToX87Register(output), Operand(esp, 0), kX87IntOperand);
4938 __ pop(input_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004939 } else {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004940 X87Mov(ToX87Register(output), ToOperand(input), kX87IntOperand);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004941 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004942}
4943
4944
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004945void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4946 Register input = ToRegister(instr->value());
4947 __ SmiTag(input);
4948 if (!instr->hydrogen()->value()->HasRange() ||
4949 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4950 DeoptimizeIf(overflow, instr->environment());
4951 }
4952}
4953
4954
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004955void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004956 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004957 LOperand* output = instr->result();
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004958 if (CpuFeatures::IsSupported(SSE2)) {
4959 CpuFeatureScope scope(masm(), SSE2);
4960 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004961
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00004962 __ LoadUint32(ToDoubleRegister(output),
4963 ToRegister(input),
4964 ToDoubleRegister(temp));
4965 } else {
4966 X87Register res = ToX87Register(output);
4967 X87PrepareToWrite(res);
4968 __ LoadUint32NoSSE2(ToRegister(input));
4969 X87CommitWrite(res);
4970 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004971}
4972
4973
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00004974void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4975 Register input = ToRegister(instr->value());
4976 if (!instr->hydrogen()->value()->HasRange() ||
4977 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4978 __ test(input, Immediate(0xc0000000));
4979 DeoptimizeIf(not_zero, instr->environment());
4980 }
4981 __ SmiTag(input);
4982}
4983
4984
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004985void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004986 class DeferredNumberTagI V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004987 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004988 DeferredNumberTagI(LCodeGen* codegen,
4989 LNumberTagI* instr,
4990 const X87Stack& x87_stack)
4991 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004992 virtual void Generate() V8_OVERRIDE {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004993 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), SIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004994 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004995 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004996 private:
4997 LNumberTagI* instr_;
4998 };
4999
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005000 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005001 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5002 Register reg = ToRegister(input);
5003
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005004 DeferredNumberTagI* deferred =
5005 new(zone()) DeferredNumberTagI(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005006 __ SmiTag(reg);
5007 __ j(overflow, deferred->entry());
5008 __ bind(deferred->exit());
5009}
5010
5011
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005012void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005013 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005014 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005015 DeferredNumberTagU(LCodeGen* codegen,
5016 LNumberTagU* instr,
5017 const X87Stack& x87_stack)
5018 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005019 virtual void Generate() V8_OVERRIDE {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005020 codegen()->DoDeferredNumberTagI(instr_, instr_->value(), UNSIGNED_INT32);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005021 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005022 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005023 private:
5024 LNumberTagU* instr_;
5025 };
5026
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005027 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005028 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5029 Register reg = ToRegister(input);
5030
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005031 DeferredNumberTagU* deferred =
5032 new(zone()) DeferredNumberTagU(this, instr, x87_stack_);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005033 __ cmp(reg, Immediate(Smi::kMaxValue));
5034 __ j(above, deferred->entry());
5035 __ SmiTag(reg);
5036 __ bind(deferred->exit());
5037}
5038
5039
5040void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
5041 LOperand* value,
5042 IntegerSignedness signedness) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005043 Label slow;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005044 Register reg = ToRegister(value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005045 Register tmp = reg.is(eax) ? ecx : eax;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005046 XMMRegister xmm_scratch = double_scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005047
5048 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005049 PushSafepointRegistersScope scope(this);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005050
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005051 Label done;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005052
5053 if (signedness == SIGNED_INT32) {
5054 // There was overflow, so bits 30 and 31 of the original integer
5055 // disagree. Try to allocate a heap number in new space and store
5056 // the value in there. If that fails, call the runtime system.
5057 __ SmiUntag(reg);
5058 __ xor_(reg, 0x80000000);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005059 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005060 CpuFeatureScope feature_scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005061 __ Cvtsi2sd(xmm_scratch, Operand(reg));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005062 } else {
5063 __ push(reg);
5064 __ fild_s(Operand(esp, 0));
5065 __ pop(reg);
5066 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005067 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005068 if (CpuFeatures::IsSupported(SSE2)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005069 CpuFeatureScope feature_scope(masm(), SSE2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005070 __ LoadUint32(xmm_scratch, reg,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005071 ToDoubleRegister(LNumberTagU::cast(instr)->temp()));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005072 } else {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005073 // There's no fild variant for unsigned values, so zero-extend to a 64-bit
5074 // int manually.
5075 __ push(Immediate(0));
5076 __ push(reg);
5077 __ fild_d(Operand(esp, 0));
5078 __ pop(reg);
5079 __ pop(reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005080 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005081 }
5082
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005083 if (FLAG_inline_new) {
5084 __ AllocateHeapNumber(reg, tmp, no_reg, &slow);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005085 __ jmp(&done, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005086 }
5087
5088 // Slow case: Call the runtime system to do the number allocation.
5089 __ bind(&slow);
5090
5091 // TODO(3095996): Put a valid pointer value in the stack slot where the result
5092 // register is stored, as this register is in the pointer map, but contains an
5093 // integer value.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005094 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005095 // NumberTagI and NumberTagD use the context from the frame, rather than
5096 // the environment's HContext or HInlinedContext value.
5097 // They only call Runtime::kAllocateHeapNumber.
5098 // The corresponding HChange instructions are added in a phase that does
5099 // not have easy access to the local context.
5100 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5101 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
5102 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005103 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005104 if (!reg.is(eax)) __ mov(reg, eax);
5105
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005106 // Done. Put the value in xmm_scratch into the value of the allocated heap
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005107 // number.
5108 __ bind(&done);
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);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005111 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), xmm_scratch);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005112 } else {
5113 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
5114 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005115 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005116}
5117
5118
5119void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005120 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005121 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005122 DeferredNumberTagD(LCodeGen* codegen,
5123 LNumberTagD* instr,
5124 const X87Stack& x87_stack)
5125 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005126 virtual void Generate() V8_OVERRIDE {
5127 codegen()->DoDeferredNumberTagD(instr_);
5128 }
5129 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005130 private:
5131 LNumberTagD* instr_;
5132 };
5133
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005134 Register reg = ToRegister(instr->result());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005135
danno@chromium.org169691d2013-07-15 08:01:13 +00005136 bool use_sse2 = CpuFeatures::IsSupported(SSE2);
5137 if (!use_sse2) {
5138 // Put the value to the top of stack
5139 X87Register src = ToX87Register(instr->value());
5140 X87LoadForUsage(src);
5141 }
5142
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005143 DeferredNumberTagD* deferred =
5144 new(zone()) DeferredNumberTagD(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005145 if (FLAG_inline_new) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +00005146 Register tmp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005147 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry());
5148 } else {
5149 __ jmp(deferred->entry());
5150 }
5151 __ bind(deferred->exit());
danno@chromium.org169691d2013-07-15 08:01:13 +00005152 if (use_sse2) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005153 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005154 XMMRegister input_reg = ToDoubleRegister(instr->value());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005155 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005156 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +00005157 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005158 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005159}
5160
5161
5162void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
5163 // TODO(3095996): Get rid of this. For now, we need to make the
5164 // result register contain a valid pointer because it is already
5165 // contained in the register pointer map.
5166 Register reg = ToRegister(instr->result());
5167 __ Set(reg, Immediate(0));
5168
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00005169 PushSafepointRegistersScope scope(this);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005170 // NumberTagI and NumberTagD use the context from the frame, rather than
5171 // the environment's HContext or HInlinedContext value.
5172 // They only call Runtime::kAllocateHeapNumber.
5173 // The corresponding HChange instructions are added in a phase that does
5174 // not have easy access to the local context.
5175 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
5176 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005177 RecordSafepointWithRegisters(
5178 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005179 __ StoreToSafepointRegisterSlot(reg, eax);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005180}
5181
5182
5183void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005184 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005185 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5186 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
5187 __ SmiTag(ToRegister(input));
5188}
5189
5190
5191void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005192 LOperand* input = instr->value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005193 Register result = ToRegister(input);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005194 ASSERT(input->IsRegister() && input->Equals(instr->result()));
5195 if (instr->needs_check()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005196 __ test(result, Immediate(kSmiTagMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005197 DeoptimizeIf(not_zero, instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005198 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005199 __ AssertSmi(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005200 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005201 __ SmiUntag(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005202}
5203
5204
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005205void LCodeGen::EmitNumberUntagDNoSSE2(Register input_reg,
5206 Register temp_reg,
danno@chromium.org169691d2013-07-15 08:01:13 +00005207 X87Register res_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005208 bool can_convert_undefined_to_nan,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005209 bool deoptimize_on_minus_zero,
5210 LEnvironment* env,
5211 NumberUntagDMode mode) {
5212 Label load_smi, done;
5213
danno@chromium.org169691d2013-07-15 08:01:13 +00005214 X87PrepareToWrite(res_reg);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005215 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005216 // Smi check.
5217 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
5218
5219 // Heap number map check.
5220 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5221 factory()->heap_number_map());
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005222 if (!can_convert_undefined_to_nan) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005223 DeoptimizeIf(not_equal, env);
5224 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005225 Label heap_number, convert;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005226 __ j(equal, &heap_number, Label::kNear);
5227
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005228 // Convert undefined (or hole) to NaN.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005229 __ cmp(input_reg, factory()->undefined_value());
5230 DeoptimizeIf(not_equal, env);
5231
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005232 __ bind(&convert);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005233 ExternalReference nan =
5234 ExternalReference::address_of_canonical_non_hole_nan();
5235 __ fld_d(Operand::StaticVariable(nan));
5236 __ jmp(&done, Label::kNear);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005237
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005238 __ bind(&heap_number);
5239 }
5240 // Heap number to x87 conversion.
5241 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5242 if (deoptimize_on_minus_zero) {
5243 __ fldz();
5244 __ FCmp();
5245 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
5246 __ j(not_zero, &done, Label::kNear);
5247
5248 // Use general purpose registers to check if we have -0.0
5249 __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5250 __ test(temp_reg, Immediate(HeapNumber::kSignMask));
5251 __ j(zero, &done, Label::kNear);
5252
5253 // Pop FPU stack before deoptimizing.
5254 __ fstp(0);
5255 DeoptimizeIf(not_zero, env);
5256 }
5257 __ jmp(&done, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005258 } else {
5259 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
5260 }
5261
5262 __ bind(&load_smi);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005263 // Clobbering a temp is faster than re-tagging the
5264 // input register since we avoid dependencies.
5265 __ mov(temp_reg, input_reg);
5266 __ SmiUntag(temp_reg); // Untag smi before converting to float.
5267 __ push(temp_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005268 __ fild_s(Operand(esp, 0));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005269 __ add(esp, Immediate(kPointerSize));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005270 __ bind(&done);
danno@chromium.org169691d2013-07-15 08:01:13 +00005271 X87CommitWrite(res_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005272}
5273
5274
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005275void LCodeGen::EmitNumberUntagD(Register input_reg,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005276 Register temp_reg,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005277 XMMRegister result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005278 bool can_convert_undefined_to_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005279 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005280 LEnvironment* env,
5281 NumberUntagDMode mode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005282 Label convert, load_smi, done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005283
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005284 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005285 // Smi check.
5286 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005287
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005288 // Heap number map check.
5289 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5290 factory()->heap_number_map());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005291 if (can_convert_undefined_to_nan) {
5292 __ j(not_equal, &convert, Label::kNear);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005293 } else {
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005294 DeoptimizeIf(not_equal, env);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00005295 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005296
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005297 // Heap number to XMM conversion.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005298 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005299
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005300 if (deoptimize_on_minus_zero) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005301 XMMRegister xmm_scratch = double_scratch0();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005302 __ xorps(xmm_scratch, xmm_scratch);
5303 __ ucomisd(result_reg, xmm_scratch);
5304 __ j(not_zero, &done, Label::kNear);
5305 __ movmskpd(temp_reg, result_reg);
5306 __ test_b(temp_reg, 1);
5307 DeoptimizeIf(not_zero, env);
5308 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005309 __ jmp(&done, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005310
5311 if (can_convert_undefined_to_nan) {
5312 __ bind(&convert);
5313
5314 // Convert undefined (and hole) to NaN.
5315 __ cmp(input_reg, factory()->undefined_value());
5316 DeoptimizeIf(not_equal, env);
5317
5318 ExternalReference nan =
5319 ExternalReference::address_of_canonical_non_hole_nan();
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005320 __ movsd(result_reg, Operand::StaticVariable(nan));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005321 __ jmp(&done, Label::kNear);
5322 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005323 } else {
5324 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005325 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005326
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005327 __ bind(&load_smi);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005328 // Smi to XMM conversion. Clobbering a temp is faster than re-tagging the
5329 // input register since we avoid dependencies.
5330 __ mov(temp_reg, input_reg);
5331 __ SmiUntag(temp_reg); // Untag smi before converting to float.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005332 __ Cvtsi2sd(result_reg, Operand(temp_reg));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005333 __ bind(&done);
5334}
5335
5336
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005337void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005338 Register input_reg = ToRegister(instr->value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005339
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005340 if (instr->truncating()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005341 Label no_heap_number, check_bools, check_false;
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005342
5343 // Heap number map check.
5344 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5345 factory()->heap_number_map());
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005346 __ j(not_equal, &no_heap_number, Label::kNear);
5347 __ TruncateHeapNumberToI(input_reg, input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005348 __ jmp(done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005349
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00005350 __ bind(&no_heap_number);
5351 // Check for Oddballs. Undefined/False is converted to zero and True to one
5352 // for truncating conversions.
5353 __ cmp(input_reg, factory()->undefined_value());
5354 __ j(not_equal, &check_bools, Label::kNear);
5355 __ Set(input_reg, Immediate(0));
5356 __ jmp(done);
5357
5358 __ bind(&check_bools);
5359 __ cmp(input_reg, factory()->true_value());
5360 __ j(not_equal, &check_false, Label::kNear);
5361 __ Set(input_reg, Immediate(1));
5362 __ jmp(done);
5363
5364 __ bind(&check_false);
5365 __ cmp(input_reg, factory()->false_value());
5366 __ RecordComment("Deferred TaggedToI: cannot truncate");
5367 DeoptimizeIf(not_equal, instr->environment());
5368 __ Set(input_reg, Immediate(0));
5369 __ jmp(done);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005370 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005371 Label bailout;
5372 XMMRegister scratch = (instr->temp() != NULL)
5373 ? ToDoubleRegister(instr->temp())
5374 : no_xmm_reg;
5375 __ TaggedToI(input_reg, input_reg, scratch,
5376 instr->hydrogen()->GetMinusZeroMode(), &bailout);
5377 __ jmp(done);
5378 __ bind(&bailout);
5379 DeoptimizeIf(no_condition, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005380 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005381}
5382
5383
5384void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005385 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005386 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005387 DeferredTaggedToI(LCodeGen* codegen,
5388 LTaggedToI* instr,
5389 const X87Stack& x87_stack)
5390 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005391 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005392 codegen()->DoDeferredTaggedToI(instr_, done());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005393 }
5394 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005395 private:
5396 LTaggedToI* instr_;
5397 };
5398
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005399 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005400 ASSERT(input->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005401 Register input_reg = ToRegister(input);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005402 ASSERT(input_reg.is(ToRegister(instr->result())));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005403
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005404 if (instr->hydrogen()->value()->representation().IsSmi()) {
5405 __ SmiUntag(input_reg);
5406 } else {
5407 DeferredTaggedToI* deferred =
5408 new(zone()) DeferredTaggedToI(this, instr, x87_stack_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005409
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005410 __ JumpIfNotSmi(input_reg, deferred->entry());
5411 __ SmiUntag(input_reg);
5412 __ bind(deferred->exit());
5413 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005414}
5415
5416
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005417void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005418 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005419 ASSERT(input->IsRegister());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005420 LOperand* temp = instr->temp();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005421 ASSERT(temp->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005422 LOperand* result = instr->result();
5423 ASSERT(result->IsDoubleRegister());
5424
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005425 Register input_reg = ToRegister(input);
5426 bool deoptimize_on_minus_zero =
5427 instr->hydrogen()->deoptimize_on_minus_zero();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00005428 Register temp_reg = ToRegister(temp);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005429
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005430 HValue* value = instr->hydrogen()->value();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005431 NumberUntagDMode mode = value->representation().IsSmi()
5432 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005433
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005434 if (CpuFeatures::IsSupported(SSE2)) {
5435 CpuFeatureScope scope(masm(), SSE2);
5436 XMMRegister result_reg = ToDoubleRegister(result);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005437 EmitNumberUntagD(input_reg,
5438 temp_reg,
5439 result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005440 instr->hydrogen()->can_convert_undefined_to_nan(),
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005441 deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005442 instr->environment(),
5443 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005444 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005445 EmitNumberUntagDNoSSE2(input_reg,
5446 temp_reg,
danno@chromium.org169691d2013-07-15 08:01:13 +00005447 ToX87Register(instr->result()),
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00005448 instr->hydrogen()->can_convert_undefined_to_nan(),
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005449 deoptimize_on_minus_zero,
5450 instr->environment(),
5451 mode);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005452 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005453}
5454
5455
5456void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005457 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005458 ASSERT(input->IsDoubleRegister());
5459 LOperand* result = instr->result();
5460 ASSERT(result->IsRegister());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005461 Register result_reg = ToRegister(result);
5462
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005463 if (instr->truncating()) {
5464 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5465 CpuFeatureScope scope(masm(), SSE2);
5466 XMMRegister input_reg = ToDoubleRegister(input);
5467 __ TruncateDoubleToI(result_reg, input_reg);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005468 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005469 X87Register input_reg = ToX87Register(input);
5470 X87Fxch(input_reg);
5471 __ TruncateX87TOSToI(result_reg);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005472 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005473 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005474 Label bailout, done;
5475 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5476 CpuFeatureScope scope(masm(), SSE2);
5477 XMMRegister input_reg = ToDoubleRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005478 XMMRegister xmm_scratch = double_scratch0();
5479 __ DoubleToI(result_reg, input_reg, xmm_scratch,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005480 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005481 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005482 X87Register input_reg = ToX87Register(input);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005483 X87Fxch(input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005484 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
5485 &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005486 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005487 __ jmp(&done, Label::kNear);
5488 __ bind(&bailout);
5489 DeoptimizeIf(no_condition, instr->environment());
5490 __ bind(&done);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005491 }
5492}
5493
5494
5495void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5496 LOperand* input = instr->value();
5497 ASSERT(input->IsDoubleRegister());
5498 LOperand* result = instr->result();
5499 ASSERT(result->IsRegister());
5500 Register result_reg = ToRegister(result);
5501
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005502 Label bailout, done;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005503 if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
5504 CpuFeatureScope scope(masm(), SSE2);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005505 XMMRegister input_reg = ToDoubleRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005506 XMMRegister xmm_scratch = double_scratch0();
5507 __ DoubleToI(result_reg, input_reg, xmm_scratch,
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005508 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005509 } else {
5510 X87Register input_reg = ToX87Register(input);
5511 X87Fxch(input_reg);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005512 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
5513 &bailout, Label::kNear);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005514 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005515 __ jmp(&done, Label::kNear);
5516 __ bind(&bailout);
5517 DeoptimizeIf(no_condition, instr->environment());
5518 __ bind(&done);
5519
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005520 __ SmiTag(result_reg);
5521 DeoptimizeIf(overflow, instr->environment());
5522}
5523
5524
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005525void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005526 LOperand* input = instr->value();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005527 __ test(ToOperand(input), Immediate(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005528 DeoptimizeIf(not_zero, instr->environment());
5529}
5530
5531
5532void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005533 if (!instr->hydrogen()->value()->IsHeapObject()) {
5534 LOperand* input = instr->value();
5535 __ test(ToOperand(input), Immediate(kSmiTagMask));
5536 DeoptimizeIf(zero, instr->environment());
5537 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005538}
5539
5540
5541void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005542 Register input = ToRegister(instr->value());
5543 Register temp = ToRegister(instr->temp());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005544
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005545 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005546
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005547 if (instr->hydrogen()->is_interval_check()) {
5548 InstanceType first;
5549 InstanceType last;
5550 instr->hydrogen()->GetCheckInterval(&first, &last);
5551
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005552 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5553 static_cast<int8_t>(first));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005554
5555 // If there is only one type in the interval check for equality.
5556 if (first == last) {
5557 DeoptimizeIf(not_equal, instr->environment());
5558 } else {
5559 DeoptimizeIf(below, instr->environment());
5560 // Omit check for the last type.
5561 if (last != LAST_TYPE) {
5562 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset),
5563 static_cast<int8_t>(last));
5564 DeoptimizeIf(above, instr->environment());
5565 }
5566 }
5567 } else {
5568 uint8_t mask;
5569 uint8_t tag;
5570 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5571
5572 if (IsPowerOf2(mask)) {
5573 ASSERT(tag == 0 || IsPowerOf2(tag));
5574 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask);
5575 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
5576 } else {
5577 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset));
5578 __ and_(temp, mask);
yangguo@chromium.org56454712012-02-16 15:33:53 +00005579 __ cmp(temp, tag);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005580 DeoptimizeIf(not_equal, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005581 }
5582 }
5583}
5584
5585
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005586void LCodeGen::DoCheckValue(LCheckValue* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005587 Handle<HeapObject> object = instr->hydrogen()->object().handle();
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005588 if (instr->hydrogen()->object_in_new_space()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005589 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005590 Handle<Cell> cell = isolate()->factory()->NewCell(object);
danno@chromium.org41728482013-06-12 22:31:22 +00005591 __ cmp(reg, Operand::ForCell(cell));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005592 } else {
5593 Operand operand = ToOperand(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005594 __ cmp(operand, object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005595 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005596 DeoptimizeIf(not_equal, instr->environment());
5597}
5598
5599
danno@chromium.org59400602013-08-13 17:09:37 +00005600void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5601 {
5602 PushSafepointRegistersScope scope(this);
5603 __ push(object);
5604 __ xor_(esi, esi);
5605 __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance);
5606 RecordSafepointWithRegisters(
5607 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
5608
5609 __ test(eax, Immediate(kSmiTagMask));
5610 }
5611 DeoptimizeIf(zero, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005612}
5613
5614
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005615void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005616 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00005617 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005618 DeferredCheckMaps(LCodeGen* codegen,
5619 LCheckMaps* instr,
5620 Register object,
5621 const X87Stack& x87_stack)
5622 : LDeferredCode(codegen, x87_stack), instr_(instr), object_(object) {
danno@chromium.org59400602013-08-13 17:09:37 +00005623 SetExit(check_maps());
5624 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005625 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00005626 codegen()->DoDeferredInstanceMigration(instr_, object_);
5627 }
5628 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005629 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00005630 private:
5631 LCheckMaps* instr_;
5632 Label check_maps_;
5633 Register object_;
5634 };
5635
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005636 if (instr->hydrogen()->CanOmitMapChecks()) return;
danno@chromium.org59400602013-08-13 17:09:37 +00005637
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005638 LOperand* input = instr->value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639 ASSERT(input->IsRegister());
5640 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005641
danno@chromium.org59400602013-08-13 17:09:37 +00005642 DeferredCheckMaps* deferred = NULL;
5643 if (instr->hydrogen()->has_migration_target()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005644 deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_);
danno@chromium.org59400602013-08-13 17:09:37 +00005645 __ bind(deferred->check_maps());
5646 }
5647
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005648 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005649 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005650 for (int i = 0; i < map_set.size() - 1; i++) {
5651 Handle<Map> map = map_set.at(i).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005652 __ CompareMap(reg, map);
5653 __ j(equal, &success, Label::kNear);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005654 }
danno@chromium.org59400602013-08-13 17:09:37 +00005655
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005656 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005657 __ CompareMap(reg, map);
danno@chromium.org59400602013-08-13 17:09:37 +00005658 if (instr->hydrogen()->has_migration_target()) {
5659 __ j(not_equal, deferred->entry());
5660 } else {
5661 DeoptimizeIf(not_equal, instr->environment());
5662 }
5663
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005664 __ bind(&success);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005665}
5666
5667
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005668void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005669 CpuFeatureScope scope(masm(), SSE2);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005670 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005671 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005672 Register result_reg = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005673 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005674}
5675
5676
5677void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5678 ASSERT(instr->unclamped()->Equals(instr->result()));
5679 Register value_reg = ToRegister(instr->result());
5680 __ ClampUint8(value_reg);
5681}
5682
5683
5684void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005685 CpuFeatureScope scope(masm(), SSE2);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005686
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005687 ASSERT(instr->unclamped()->Equals(instr->result()));
5688 Register input_reg = ToRegister(instr->unclamped());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005689 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005690 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005691 Label is_smi, done, heap_number;
5692
5693 __ JumpIfSmi(input_reg, &is_smi);
5694
5695 // Check for heap number
5696 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5697 factory()->heap_number_map());
5698 __ j(equal, &heap_number, Label::kNear);
5699
5700 // Check for undefined. Undefined is converted to zero for clamping
5701 // conversions.
5702 __ cmp(input_reg, factory()->undefined_value());
5703 DeoptimizeIf(not_equal, instr->environment());
5704 __ mov(input_reg, 0);
5705 __ jmp(&done, Label::kNear);
5706
5707 // Heap number
5708 __ bind(&heap_number);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00005709 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005710 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005711 __ jmp(&done, Label::kNear);
5712
5713 // smi
5714 __ bind(&is_smi);
5715 __ SmiUntag(input_reg);
5716 __ ClampUint8(input_reg);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005717 __ bind(&done);
5718}
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005719
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005720
5721void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
5722 Register input_reg = ToRegister(instr->unclamped());
5723 Register result_reg = ToRegister(instr->result());
5724 Register scratch = ToRegister(instr->scratch());
5725 Register scratch2 = ToRegister(instr->scratch2());
5726 Register scratch3 = ToRegister(instr->scratch3());
5727 Label is_smi, done, heap_number, valid_exponent,
5728 largest_value, zero_result, maybe_nan_or_infinity;
5729
5730 __ JumpIfSmi(input_reg, &is_smi);
5731
5732 // Check for heap number
5733 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5734 factory()->heap_number_map());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005735 __ j(equal, &heap_number, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005736
5737 // Check for undefined. Undefined is converted to zero for clamping
5738 // conversions.
5739 __ cmp(input_reg, factory()->undefined_value());
5740 DeoptimizeIf(not_equal, instr->environment());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005741 __ jmp(&zero_result, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005742
5743 // Heap number
5744 __ bind(&heap_number);
5745
5746 // Surprisingly, all of the hand-crafted bit-manipulations below are much
5747 // faster than the x86 FPU built-in instruction, especially since "banker's
5748 // rounding" would be additionally very expensive
5749
5750 // Get exponent word.
5751 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
5752 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
5753
5754 // Test for negative values --> clamp to zero
5755 __ test(scratch, scratch);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005756 __ j(negative, &zero_result, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005757
5758 // Get exponent alone in scratch2.
5759 __ mov(scratch2, scratch);
5760 __ and_(scratch2, HeapNumber::kExponentMask);
5761 __ shr(scratch2, HeapNumber::kExponentShift);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005762 __ j(zero, &zero_result, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005763 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005764 __ j(negative, &zero_result, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005765
5766 const uint32_t non_int8_exponent = 7;
5767 __ cmp(scratch2, Immediate(non_int8_exponent + 1));
5768 // If the exponent is too big, check for special values.
5769 __ j(greater, &maybe_nan_or_infinity, Label::kNear);
5770
5771 __ bind(&valid_exponent);
5772 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent
5773 // < 7. The shift bias is the number of bits to shift the mantissa such that
5774 // with an exponent of 7 such the that top-most one is in bit 30, allowing
5775 // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to
5776 // 1).
5777 int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1;
5778 __ lea(result_reg, MemOperand(scratch2, shift_bias));
5779 // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the
5780 // top bits of the mantissa.
5781 __ and_(scratch, HeapNumber::kMantissaMask);
5782 // Put back the implicit 1 of the mantissa
5783 __ or_(scratch, 1 << HeapNumber::kExponentShift);
5784 // Shift up to round
5785 __ shl_cl(scratch);
5786 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then
5787 // use the bit in the "ones" place and add it to the "halves" place, which has
5788 // the effect of rounding to even.
5789 __ mov(scratch2, scratch);
5790 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8;
5791 const uint32_t one_bit_shift = one_half_bit_shift + 1;
5792 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1));
5793 __ cmp(scratch2, Immediate(1 << one_half_bit_shift));
5794 Label no_round;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005795 __ j(less, &no_round, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005796 Label round_up;
5797 __ mov(scratch2, Immediate(1 << one_half_bit_shift));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005798 __ j(greater, &round_up, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005799 __ test(scratch3, scratch3);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005800 __ j(not_zero, &round_up, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005801 __ mov(scratch2, scratch);
5802 __ and_(scratch2, Immediate(1 << one_bit_shift));
5803 __ shr(scratch2, 1);
5804 __ bind(&round_up);
5805 __ add(scratch, scratch2);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005806 __ j(overflow, &largest_value, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005807 __ bind(&no_round);
5808 __ shr(scratch, 23);
5809 __ mov(result_reg, scratch);
5810 __ jmp(&done, Label::kNear);
5811
5812 __ bind(&maybe_nan_or_infinity);
5813 // Check for NaN/Infinity, all other values map to 255
5814 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1));
5815 __ j(not_equal, &largest_value, Label::kNear);
5816
5817 // Check for NaN, which differs from Infinity in that at least one mantissa
5818 // bit is set.
5819 __ and_(scratch, HeapNumber::kMantissaMask);
5820 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005821 __ j(not_zero, &zero_result, Label::kNear); // M!=0 --> NaN
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005822 // Infinity -> Fall through to map to 255.
5823
5824 __ bind(&largest_value);
5825 __ mov(result_reg, Immediate(255));
5826 __ jmp(&done, Label::kNear);
5827
5828 __ bind(&zero_result);
5829 __ xor_(result_reg, result_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005830 __ jmp(&done, Label::kNear);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005831
5832 // smi
5833 __ bind(&is_smi);
5834 if (!input_reg.is(result_reg)) {
5835 __ mov(result_reg, input_reg);
5836 }
5837 __ SmiUntag(result_reg);
5838 __ ClampUint8(result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005839 __ bind(&done);
5840}
5841
5842
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005843void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005844 class DeferredAllocate V8_FINAL : public LDeferredCode {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005845 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005846 DeferredAllocate(LCodeGen* codegen,
5847 LAllocate* instr,
5848 const X87Stack& x87_stack)
5849 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005850 virtual void Generate() V8_OVERRIDE {
5851 codegen()->DoDeferredAllocate(instr_);
5852 }
5853 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005854 private:
5855 LAllocate* instr_;
5856 };
5857
5858 DeferredAllocate* deferred =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005859 new(zone()) DeferredAllocate(this, instr, x87_stack_);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005860
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005861 Register result = ToRegister(instr->result());
5862 Register temp = ToRegister(instr->temp());
5863
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005864 // Allocate memory for the object.
5865 AllocationFlags flags = TAG_OBJECT;
5866 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5867 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5868 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005869 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5870 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5871 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005872 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005873 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5874 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005875 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005876 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005877
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005878 if (instr->size()->IsConstantOperand()) {
5879 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005880 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005881 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005882 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005883 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005884 }
5885
5886 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005887
5888 if (instr->hydrogen()->MustPrefillWithFiller()) {
5889 if (instr->size()->IsConstantOperand()) {
5890 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5891 __ mov(temp, (size / kPointerSize) - 1);
5892 } else {
5893 temp = ToRegister(instr->size());
5894 __ shr(temp, kPointerSizeLog2);
5895 __ dec(temp);
5896 }
5897 Label loop;
5898 __ bind(&loop);
5899 __ mov(FieldOperand(result, temp, times_pointer_size, 0),
5900 isolate()->factory()->one_pointer_filler_map());
5901 __ dec(temp);
5902 __ j(not_zero, &loop);
5903 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005904}
5905
5906
5907void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005908 Register result = ToRegister(instr->result());
5909
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005910 // TODO(3095996): Get rid of this. For now, we need to make the
5911 // result register contain a valid pointer because it is already
5912 // contained in the register pointer map.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005913 __ Set(result, Immediate(Smi::FromInt(0)));
danno@chromium.orgf005df62013-04-30 16:36:45 +00005914
5915 PushSafepointRegistersScope scope(this);
5916 if (instr->size()->IsRegister()) {
5917 Register size = ToRegister(instr->size());
5918 ASSERT(!size.is(result));
5919 __ SmiTag(ToRegister(instr->size()));
5920 __ push(size);
5921 } else {
5922 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5923 __ push(Immediate(Smi::FromInt(size)));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005924 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00005925
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005926 int flags = AllocateDoubleAlignFlag::encode(
5927 instr->hydrogen()->MustAllocateDoubleAligned());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005928 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5929 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5930 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005931 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005932 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5933 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005934 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005935 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005936 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005937 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005938 __ push(Immediate(Smi::FromInt(flags)));
5939
5940 CallRuntimeFromDeferred(
5941 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005942 __ StoreToSafepointRegisterSlot(result, eax);
5943}
5944
5945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005946void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005947 ASSERT(ToRegister(instr->value()).is(eax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005948 __ push(eax);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005949 CallRuntime(Runtime::kToFastProperties, 1, instr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950}
5951
5952
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005953void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005954 ASSERT(ToRegister(instr->context()).is(esi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005955 Label materialized;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005956 // Registers will be used as follows:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005957 // ecx = literals array.
5958 // ebx = regexp literal.
5959 // eax = regexp literal clone.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005960 // esi = context.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005961 int literal_offset =
5962 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5963 __ LoadHeapObject(ecx, instr->hydrogen()->literals());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005964 __ mov(ebx, FieldOperand(ecx, literal_offset));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005965 __ cmp(ebx, factory()->undefined_value());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005966 __ j(not_equal, &materialized, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005967
5968 // Create regexp literal using runtime function
5969 // Result will be in eax.
5970 __ push(ecx);
5971 __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
5972 __ push(Immediate(instr->hydrogen()->pattern()));
5973 __ push(Immediate(instr->hydrogen()->flags()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005974 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005975 __ mov(ebx, eax);
5976
5977 __ bind(&materialized);
5978 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5979 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005980 __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005981 __ jmp(&allocated, Label::kNear);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005982
5983 __ bind(&runtime_allocate);
5984 __ push(ebx);
5985 __ push(Immediate(Smi::FromInt(size)));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00005986 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005987 __ pop(ebx);
5988
5989 __ bind(&allocated);
5990 // Copy the content into the newly allocated memory.
5991 // (Unroll copy loop once for better throughput).
5992 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5993 __ mov(edx, FieldOperand(ebx, i));
5994 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
5995 __ mov(FieldOperand(eax, i), edx);
5996 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
5997 }
5998 if ((size % (2 * kPointerSize)) != 0) {
5999 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
6000 __ mov(FieldOperand(eax, size - kPointerSize), edx);
6001 }
6002}
6003
6004
6005void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006006 ASSERT(ToRegister(instr->context()).is(esi));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006007 // Use the fast case closure allocation code that allocates in new
6008 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006009 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006010 if (!pretenure && instr->hydrogen()->has_no_literals()) {
6011 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
6012 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00006013 __ mov(ebx, Immediate(instr->hydrogen()->shared_info()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00006014 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006015 } else {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006016 __ push(esi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006017 __ push(Immediate(instr->hydrogen()->shared_info()));
6018 __ push(Immediate(pretenure ? factory()->true_value()
6019 : factory()->false_value()));
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006020 CallRuntime(Runtime::kNewClosure, 3, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006021 }
6022}
6023
6024
6025void LCodeGen::DoTypeof(LTypeof* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006026 ASSERT(ToRegister(instr->context()).is(esi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006027 LOperand* input = instr->value();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006028 EmitPushTaggedOperand(input);
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006029 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006030}
6031
6032
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006033void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006034 Register input = ToRegister(instr->value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006035 Condition final_branch_condition = EmitTypeofIs(instr, input);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006036 if (final_branch_condition != no_condition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006037 EmitBranch(instr, final_branch_condition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006038 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006039}
6040
6041
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006042Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
6043 Label* true_label = instr->TrueLabel(chunk_);
6044 Label* false_label = instr->FalseLabel(chunk_);
6045 Handle<String> type_name = instr->type_literal();
6046 int left_block = instr->TrueDestination(chunk_);
6047 int right_block = instr->FalseDestination(chunk_);
6048 int next_block = GetNextEmittedBlock();
6049
6050 Label::Distance true_distance = left_block == next_block ? Label::kNear
6051 : Label::kFar;
6052 Label::Distance false_distance = right_block == next_block ? Label::kNear
6053 : Label::kFar;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006054 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006055 if (type_name->Equals(heap()->number_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006056 __ JumpIfSmi(input, true_label, true_distance);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006057 __ cmp(FieldOperand(input, HeapObject::kMapOffset),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 factory()->heap_number_map());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006059 final_branch_condition = equal;
6060
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006061 } else if (type_name->Equals(heap()->string_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006062 __ JumpIfSmi(input, false_label, false_distance);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006063 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006064 __ j(above_equal, false_label, false_distance);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006065 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6066 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006067 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006068
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006069 } else if (type_name->Equals(heap()->symbol_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006070 __ JumpIfSmi(input, false_label, false_distance);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006071 __ CmpObjectType(input, SYMBOL_TYPE, input);
6072 final_branch_condition = equal;
6073
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006074 } else if (type_name->Equals(heap()->boolean_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006075 __ cmp(input, factory()->true_value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006076 __ j(equal, true_label, true_distance);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006077 __ cmp(input, factory()->false_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006078 final_branch_condition = equal;
6079
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006080 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006081 __ cmp(input, factory()->null_value());
6082 final_branch_condition = equal;
6083
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006084 } else if (type_name->Equals(heap()->undefined_string())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 __ cmp(input, factory()->undefined_value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006086 __ j(equal, true_label, true_distance);
6087 __ JumpIfSmi(input, false_label, false_distance);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006088 // Check for undetectable objects => true.
6089 __ mov(input, FieldOperand(input, HeapObject::kMapOffset));
6090 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6091 1 << Map::kIsUndetectable);
6092 final_branch_condition = not_zero;
6093
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006094 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006095 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006096 __ JumpIfSmi(input, false_label, false_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006097 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006098 __ j(equal, true_label, true_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006099 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
6100 final_branch_condition = equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006101
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00006102 } else if (type_name->Equals(heap()->object_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006103 __ JumpIfSmi(input, false_label, false_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006104 if (!FLAG_harmony_typeof) {
6105 __ cmp(input, factory()->null_value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006106 __ j(equal, true_label, true_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006107 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00006108 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006109 __ j(below, false_label, false_distance);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00006110 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006111 __ j(above, false_label, false_distance);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006112 // Check for undetectable objects => false.
6113 __ test_b(FieldOperand(input, Map::kBitFieldOffset),
6114 1 << Map::kIsUndetectable);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006115 final_branch_condition = zero;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006116
6117 } else {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006118 __ jmp(false_label, false_distance);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006119 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006120 return final_branch_condition;
6121}
6122
6123
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006124void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006125 Register temp = ToRegister(instr->temp());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006126
6127 EmitIsConstructCall(temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006128 EmitBranch(instr, equal);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006129}
6130
6131
6132void LCodeGen::EmitIsConstructCall(Register temp) {
6133 // Get the frame pointer for the calling frame.
6134 __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
6135
6136 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006137 Label check_frame_marker;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006138 __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
6139 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00006140 __ j(not_equal, &check_frame_marker, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00006141 __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
6142
6143 // Check the marker in the calling frame.
6144 __ bind(&check_frame_marker);
6145 __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
6146 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
6147}
6148
6149
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006150void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006151 if (!info()->IsStub()) {
6152 // Ensure that we have enough space after the previous lazy-bailout
6153 // instruction for patching the code here.
6154 int current_pc = masm()->pc_offset();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006155 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
6156 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006157 __ Nop(padding_size);
6158 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006159 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00006160 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006161}
6162
6163
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006164void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006165 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006166 ASSERT(instr->HasEnvironment());
6167 LEnvironment* env = instr->environment();
6168 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6169 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006170}
6171
6172
6173void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00006174 Deoptimizer::BailoutType type = instr->hydrogen()->type();
6175 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
6176 // needed return address), even though the implementation of LAZY and EAGER is
6177 // now identical. When LAZY is eventually completely folded into EAGER, remove
6178 // the special case below.
6179 if (info()->IsStub() && type == Deoptimizer::EAGER) {
6180 type = Deoptimizer::LAZY;
danno@chromium.orgaefd6072013-05-14 14:11:47 +00006181 }
danno@chromium.org59400602013-08-13 17:09:37 +00006182 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00006183 DeoptimizeIf(no_condition, instr->environment(), type);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006184}
6185
6186
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006187void LCodeGen::DoDummy(LDummy* instr) {
6188 // Nothing to see here, move on!
6189}
6190
6191
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00006192void LCodeGen::DoDummyUse(LDummyUse* instr) {
6193 // Nothing to see here, move on!
6194}
6195
6196
ager@chromium.org04921a82011-06-27 13:21:41 +00006197void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006198 PushSafepointRegistersScope scope(this);
6199 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
6200 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
6201 RecordSafepointWithLazyDeopt(
6202 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
6203 ASSERT(instr->HasEnvironment());
6204 LEnvironment* env = instr->environment();
6205 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006206}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006207
ager@chromium.org04921a82011-06-27 13:21:41 +00006208
6209void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00006210 class DeferredStackCheck V8_FINAL : public LDeferredCode {
ager@chromium.org04921a82011-06-27 13:21:41 +00006211 public:
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006212 DeferredStackCheck(LCodeGen* codegen,
6213 LStackCheck* instr,
6214 const X87Stack& x87_stack)
6215 : LDeferredCode(codegen, x87_stack), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00006216 virtual void Generate() V8_OVERRIDE {
6217 codegen()->DoDeferredStackCheck(instr_);
6218 }
6219 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00006220 private:
6221 LStackCheck* instr_;
6222 };
6223
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006224 ASSERT(instr->HasEnvironment());
6225 LEnvironment* env = instr->environment();
6226 // There is no LLazyBailout instruction for stack-checks. We have to
6227 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00006228 if (instr->hydrogen()->is_function_entry()) {
6229 // Perform stack overflow check.
6230 Label done;
6231 ExternalReference stack_limit =
6232 ExternalReference::address_of_stack_limit(isolate());
6233 __ cmp(esp, Operand::StaticVariable(stack_limit));
6234 __ j(above_equal, &done, Label::kNear);
6235
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00006236 ASSERT(instr->context()->IsRegister());
6237 ASSERT(ToRegister(instr->context()).is(esi));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00006238 CallCode(isolate()->builtins()->StackCheck(),
6239 RelocInfo::CODE_TARGET,
6240 instr);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006241 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00006242 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006243 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6244 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00006245 } else {
6246 ASSERT(instr->hydrogen()->is_backwards_branch());
6247 // Perform stack overflow check if this goto needs it before jumping.
6248 DeferredStackCheck* deferred_stack_check =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006249 new(zone()) DeferredStackCheck(this, instr, x87_stack_);
ager@chromium.org04921a82011-06-27 13:21:41 +00006250 ExternalReference stack_limit =
6251 ExternalReference::address_of_stack_limit(isolate());
6252 __ cmp(esp, Operand::StaticVariable(stack_limit));
6253 __ j(below, deferred_stack_check->entry());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00006254 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00006255 __ bind(instr->done_label());
6256 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006257 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
6258 // Don't record a deoptimization index for the safepoint here.
6259 // This will be done explicitly when emitting call and the safepoint in
6260 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00006261 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006262}
6263
6264
6265void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
6266 // This is a pseudo-instruction that ensures that the environment here is
6267 // properly registered for deoptimization and records the assembler's PC
6268 // offset.
6269 LEnvironment* environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006270
6271 // If the environment were already registered, we would have no way of
6272 // backpatching it with the spill slot operands.
6273 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00006274 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00006275
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006276 GenerateOsrPrologue();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006277}
6278
6279
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006280void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006281 ASSERT(ToRegister(instr->context()).is(esi));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006282 __ cmp(eax, isolate()->factory()->undefined_value());
6283 DeoptimizeIf(equal, instr->environment());
6284
6285 __ cmp(eax, isolate()->factory()->null_value());
6286 DeoptimizeIf(equal, instr->environment());
6287
6288 __ test(eax, Immediate(kSmiTagMask));
6289 DeoptimizeIf(zero, instr->environment());
6290
6291 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
6292 __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
6293 DeoptimizeIf(below_equal, instr->environment());
6294
6295 Label use_cache, call_runtime;
6296 __ CheckEnumCache(&call_runtime);
6297
6298 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
6299 __ jmp(&use_cache, Label::kNear);
6300
6301 // Get the set of properties to enumerate.
6302 __ bind(&call_runtime);
6303 __ push(eax);
6304 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
6305
6306 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
6307 isolate()->factory()->meta_map());
6308 DeoptimizeIf(not_equal, instr->environment());
6309 __ bind(&use_cache);
6310}
6311
6312
6313void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
6314 Register map = ToRegister(instr->map());
6315 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006316 Label load_cache, done;
6317 __ EnumLength(result, map);
6318 __ cmp(result, Immediate(Smi::FromInt(0)));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006319 __ j(not_equal, &load_cache, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006320 __ mov(result, isolate()->factory()->empty_fixed_array());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006321 __ jmp(&done, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006322
6323 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006324 __ LoadInstanceDescriptors(map, result);
6325 __ mov(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006326 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006327 __ mov(result,
6328 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00006329 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006330 __ test(result, result);
6331 DeoptimizeIf(equal, instr->environment());
6332}
6333
6334
6335void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
6336 Register object = ToRegister(instr->value());
6337 __ cmp(ToRegister(instr->map()),
6338 FieldOperand(object, HeapObject::kMapOffset));
6339 DeoptimizeIf(not_equal, instr->environment());
6340}
6341
6342
6343void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
6344 Register object = ToRegister(instr->object());
6345 Register index = ToRegister(instr->index());
6346
6347 Label out_of_object, done;
6348 __ cmp(index, Immediate(0));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00006349 __ j(less, &out_of_object, Label::kNear);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006350 __ mov(object, FieldOperand(object,
6351 index,
6352 times_half_pointer_size,
6353 JSObject::kHeaderSize));
6354 __ jmp(&done, Label::kNear);
6355
6356 __ bind(&out_of_object);
6357 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset));
6358 __ neg(index);
6359 // Index is now equal to out of object property index plus 1.
6360 __ mov(object, FieldOperand(object,
6361 index,
6362 times_half_pointer_size,
6363 FixedArray::kHeaderSize - kPointerSize));
6364 __ bind(&done);
6365}
6366
6367
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006368#undef __
6369
6370} } // namespace v8::internal
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006371
6372#endif // V8_TARGET_ARCH_IA32