blob: e6a20f21f86a9d0e0c473bb1873720dfde06bb01 [file] [log] [blame]
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00001// Copyright 2013 the V8 project authors. All rights reserved.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +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
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_X64
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000031
32#include "x64/lithium-codegen-x64.h"
33#include "code-stubs.h"
34#include "stub-cache.h"
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000035#include "hydrogen-osr.h"
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000036
37namespace v8 {
38namespace internal {
39
40
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000041// When invoking builtins, we need to record the safepoint in the middle of
42// the invoke instruction sequence generated by the macro assembler.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000043class SafepointGenerator V8_FINAL : public CallWrapper {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000044 public:
45 SafepointGenerator(LCodeGen* codegen,
46 LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +000047 Safepoint::DeoptMode mode)
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000048 : codegen_(codegen),
49 pointers_(pointers),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000050 deopt_mode_(mode) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000051 virtual ~SafepointGenerator() {}
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000052
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000053 virtual void BeforeCall(int call_size) const V8_OVERRIDE {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000054 codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size);
55 }
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +000056
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000057 virtual void AfterCall() const V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000058 codegen_->RecordSafepoint(pointers_, deopt_mode_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000059 }
60
61 private:
62 LCodeGen* codegen_;
63 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000064 Safepoint::DeoptMode deopt_mode_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000065};
66
67
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000068#define __ masm()->
69
70bool LCodeGen::GenerateCode() {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000071 LPhase phase("Z_Code generation", chunk());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000072 ASSERT(is_unused());
73 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000074
75 // Open a frame scope to indicate that there is a frame on the stack. The
76 // MANUAL indicates that the scope shouldn't actually generate code to set up
77 // the frame (that is done in GeneratePrologue).
78 FrameScope frame_scope(masm_, StackFrame::MANUAL);
79
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000080 return GeneratePrologue() &&
81 GenerateBody() &&
82 GenerateDeferredCode() &&
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000083 GenerateJumpTable() &&
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000084 GenerateSafepointTable();
85}
86
87
88void LCodeGen::FinishCode(Handle<Code> code) {
89 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000090 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000091 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000092 RegisterDependentCodeForEmbeddedMaps(code);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000093 PopulateDeoptimizationData(code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000094 info()->CommitDependencies(code);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000095}
96
97
danno@chromium.org59400602013-08-13 17:09:37 +000098void LChunkBuilder::Abort(BailoutReason reason) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000099 info()->set_bailout_reason(reason);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000100 status_ = ABORTED;
101}
102
103
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000104#ifdef _MSC_VER
105void LCodeGen::MakeSureStackPagesMapped(int offset) {
106 const int kPageSize = 4 * KB;
107 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
108 __ movq(Operand(rsp, offset), rax);
109 }
110}
111#endif
112
113
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000114void LCodeGen::SaveCallerDoubles() {
115 ASSERT(info()->saves_caller_doubles());
116 ASSERT(NeedsEagerFrame());
117 Comment(";;; Save clobbered callee double registers");
118 int count = 0;
119 BitVector* doubles = chunk()->allocated_double_registers();
120 BitVector::Iterator save_iterator(doubles);
121 while (!save_iterator.Done()) {
122 __ movsd(MemOperand(rsp, count * kDoubleSize),
123 XMMRegister::FromAllocationIndex(save_iterator.Current()));
124 save_iterator.Advance();
125 count++;
126 }
127}
128
129
130void LCodeGen::RestoreCallerDoubles() {
131 ASSERT(info()->saves_caller_doubles());
132 ASSERT(NeedsEagerFrame());
133 Comment(";;; Restore clobbered callee double registers");
134 BitVector* doubles = chunk()->allocated_double_registers();
135 BitVector::Iterator save_iterator(doubles);
136 int count = 0;
137 while (!save_iterator.Done()) {
138 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
139 MemOperand(rsp, count * kDoubleSize));
140 save_iterator.Advance();
141 count++;
142 }
143}
144
145
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000146bool LCodeGen::GeneratePrologue() {
147 ASSERT(is_generating());
148
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000149 if (info()->IsOptimizing()) {
150 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000151
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000152#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000153 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000154 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000155 __ int3();
156 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000157#endif
158
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000159 // Strict mode functions need to replace the receiver with undefined
160 // when called as functions (without an explicit receiver
161 // object). rcx is zero for method calls and non-zero for function
162 // calls.
163 if (!info_->is_classic_mode() || info_->is_native()) {
164 Label ok;
165 __ testq(rcx, rcx);
166 __ j(zero, &ok, Label::kNear);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000167 StackArgumentsAccessor args(rsp, scope()->num_parameters());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000168 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000169 __ movq(args.GetReceiverOperand(), kScratchRegister);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000170 __ bind(&ok);
171 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000172 }
173
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000174 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000175 if (NeedsEagerFrame()) {
176 ASSERT(!frame_is_built_);
177 frame_is_built_ = true;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000178 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000179 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000180 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000181
182 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000183 int slots = GetStackSlotCount();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000184 if (slots > 0) {
185 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000186 __ subq(rsp, Immediate(slots * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000187#ifdef _MSC_VER
188 MakeSureStackPagesMapped(slots * kPointerSize);
189#endif
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000190 __ push(rax);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000191 __ Set(rax, slots);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000192 __ movq(kScratchRegister, kSlotsZapValue);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000193 Label loop;
194 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000195 __ movq(MemOperand(rsp, rax, times_pointer_size, 0),
196 kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000197 __ decl(rax);
198 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000199 __ pop(rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000200 } else {
201 __ subq(rsp, Immediate(slots * kPointerSize));
202#ifdef _MSC_VER
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000203 MakeSureStackPagesMapped(slots * kPointerSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000204#endif
205 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000206
207 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000208 SaveCallerDoubles();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000209 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000210 }
211
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000212 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000213 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000214 if (heap_slots > 0) {
215 Comment(";;; Allocate local context");
216 // Argument to NewContext is the function, which is still in rdi.
217 __ push(rdi);
218 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
219 FastNewContextStub stub(heap_slots);
220 __ CallStub(&stub);
221 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000222 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000223 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000224 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000225 // Context is returned in both rax and rsi. It replaces the context
226 // passed to us. It's saved in the stack and kept live in rsi.
227 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
228
229 // Copy any necessary parameters into the context.
230 int num_parameters = scope()->num_parameters();
231 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000232 Variable* var = scope()->parameter(i);
233 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000234 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
235 (num_parameters - 1 - i) * kPointerSize;
236 // Load parameter from stack.
237 __ movq(rax, Operand(rbp, parameter_offset));
238 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000239 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000240 __ movq(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000241 // Update the write barrier. This clobbers rax and rbx.
242 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000243 }
244 }
245 Comment(";;; End allocate local context");
246 }
247
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000248 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000249 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000250 __ CallRuntime(Runtime::kTraceEnter, 0);
251 }
252 return !is_aborted();
253}
254
255
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000256void LCodeGen::GenerateOsrPrologue() {
257 // Generate the OSR entry prologue at the first unknown OSR value, or if there
258 // are none, at the OSR entrypoint instruction.
259 if (osr_pc_offset_ >= 0) return;
260
261 osr_pc_offset_ = masm()->pc_offset();
262
263 // Adjust the frame size, subsuming the unoptimized frame into the
264 // optimized frame.
265 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
266 ASSERT(slots >= 0);
267 __ subq(rsp, Immediate(slots * kPointerSize));
268}
269
270
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000271bool LCodeGen::GenerateJumpTable() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000272 Label needs_frame;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000273 if (jump_table_.length() > 0) {
274 Comment(";;; -------------------- Jump table --------------------");
275 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000276 for (int i = 0; i < jump_table_.length(); i++) {
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000277 __ bind(&jump_table_[i].label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000278 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000279 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000280 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000281 if (id == Deoptimizer::kNotDeoptimizationEntry) {
282 Comment(";;; jump table entry %d.", i);
283 } else {
284 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
285 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000286 if (jump_table_[i].needs_frame) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000287 ASSERT(!info()->saves_caller_doubles());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000288 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
danno@chromium.org169691d2013-07-15 08:01:13 +0000289 if (needs_frame.is_bound()) {
290 __ jmp(&needs_frame);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000291 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000292 __ bind(&needs_frame);
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000293 __ movq(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.org169691d2013-07-15 08:01:13 +0000294 __ push(rbp);
295 __ movq(rbp, rsp);
296 __ push(rsi);
297 // This variant of deopt can only be used with stubs. Since we don't
298 // have a function pointer to install in the stack frame that we're
299 // building, install a special marker there instead.
300 ASSERT(info()->IsStub());
301 __ Move(rsi, Smi::FromInt(StackFrame::STUB));
302 __ push(rsi);
303 __ movq(rsi, MemOperand(rsp, kPointerSize));
304 __ call(kScratchRegister);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000305 }
306 } else {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000307 if (info()->saves_caller_doubles()) {
308 ASSERT(info()->IsStub());
309 RestoreCallerDoubles();
310 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000311 __ call(entry, RelocInfo::RUNTIME_ENTRY);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000312 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000313 }
314 return !is_aborted();
315}
316
317
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000318bool LCodeGen::GenerateDeferredCode() {
319 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000320 if (deferred_.length() > 0) {
321 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
322 LDeferredCode* code = deferred_[i];
danno@chromium.org59400602013-08-13 17:09:37 +0000323
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000324 HValue* value =
325 instructions_->at(code->instruction_index())->hydrogen_value();
326 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000327
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000328 Comment(";;; <@%d,#%d> "
329 "-------------------- Deferred %s --------------------",
330 code->instruction_index(),
331 code->instr()->hydrogen_value()->id(),
332 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000333 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000334 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000335 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000336 ASSERT(!frame_is_built_);
337 ASSERT(info()->IsStub());
338 frame_is_built_ = true;
339 // Build the frame in such a way that esi isn't trashed.
340 __ push(rbp); // Caller's frame pointer.
341 __ push(Operand(rbp, StandardFrameConstants::kContextOffset));
342 __ Push(Smi::FromInt(StackFrame::STUB));
343 __ lea(rbp, Operand(rsp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000344 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000345 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000346 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000347 if (NeedsDeferredFrame()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000348 __ bind(code->done());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000349 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000350 ASSERT(frame_is_built_);
351 frame_is_built_ = false;
352 __ movq(rsp, rbp);
353 __ pop(rbp);
354 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000355 __ jmp(code->exit());
356 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000357 }
358
359 // Deferred code is the last part of the instruction sequence. Mark
360 // the generated code as done unless we bailed out.
361 if (!is_aborted()) status_ = DONE;
362 return !is_aborted();
363}
364
365
366bool LCodeGen::GenerateSafepointTable() {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000367 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000368 safepoints_.Emit(masm(), GetStackSlotCount());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000369 return !is_aborted();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000370}
371
372
373Register LCodeGen::ToRegister(int index) const {
374 return Register::FromAllocationIndex(index);
375}
376
377
378XMMRegister LCodeGen::ToDoubleRegister(int index) const {
379 return XMMRegister::FromAllocationIndex(index);
380}
381
382
383Register LCodeGen::ToRegister(LOperand* op) const {
384 ASSERT(op->IsRegister());
385 return ToRegister(op->index());
386}
387
388
389XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
390 ASSERT(op->IsDoubleRegister());
391 return ToDoubleRegister(op->index());
392}
393
394
395bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
396 return op->IsConstantOperand() &&
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000397 chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000398}
399
400
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000401bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
402 return op->IsConstantOperand() &&
403 chunk_->LookupLiteralRepresentation(op).IsSmi();
404}
405
406
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000407bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
408 return op->IsConstantOperand() &&
409 chunk_->LookupLiteralRepresentation(op).IsTagged();
410}
411
412
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000413int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000414 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000415 return constant->Integer32Value();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000416}
417
418
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000419Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
420 HConstant* constant = chunk_->LookupConstant(op);
421 return Smi::FromInt(constant->Integer32Value());
422}
423
424
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000425double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000426 HConstant* constant = chunk_->LookupConstant(op);
427 ASSERT(constant->HasDoubleValue());
428 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000429}
430
431
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000432ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
433 HConstant* constant = chunk_->LookupConstant(op);
434 ASSERT(constant->HasExternalReferenceValue());
435 return constant->ExternalReferenceValue();
436}
437
438
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000439Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000440 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000441 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000442 return constant->handle(isolate());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000443}
444
445
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000446static int ArgumentsOffsetWithoutFrame(int index) {
447 ASSERT(index < 0);
448 return -(index + 1) * kPointerSize + kPCOnStackSize;
449}
450
451
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000452Operand LCodeGen::ToOperand(LOperand* op) const {
453 // Does not handle registers. In X64 assembler, plain registers are not
454 // representable as an Operand.
455 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000456 if (NeedsEagerFrame()) {
457 return Operand(rbp, StackSlotOffset(op->index()));
458 } else {
459 // Retrieve parameter without eager stack-frame relative to the
460 // stack-pointer.
461 return Operand(rsp, ArgumentsOffsetWithoutFrame(op->index()));
462 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000463}
464
465
466void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000467 Translation* translation) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000468 if (environment == NULL) return;
469
470 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000471 int translation_size = environment->translation_size();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000472 // The output frame height does not include the parameters.
473 int height = translation_size - environment->parameter_count();
474
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000475 WriteTranslation(environment->outer(), translation);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000476 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000477 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000478 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000479 ? DefineDeoptimizationLiteral(environment->closure())
480 : Translation::kSelfLiteralId;
481
ulan@chromium.org967e2702012-02-28 09:49:15 +0000482 switch (environment->frame_type()) {
483 case JS_FUNCTION:
484 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
485 break;
486 case JS_CONSTRUCT:
487 translation->BeginConstructStubFrame(closure_id, translation_size);
488 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000489 case JS_GETTER:
490 ASSERT(translation_size == 1);
491 ASSERT(height == 0);
492 translation->BeginGetterStubFrame(closure_id);
493 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000494 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000495 ASSERT(translation_size == 2);
496 ASSERT(height == 0);
497 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000498 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000499 case ARGUMENTS_ADAPTOR:
500 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
501 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000502 case STUB:
503 translation->BeginCompiledStubFrame();
504 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000505 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000506
danno@chromium.org59400602013-08-13 17:09:37 +0000507 int object_index = 0;
508 int dematerialized_index = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000509 for (int i = 0; i < translation_size; ++i) {
510 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000511 AddToTranslation(environment,
512 translation,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000513 value,
514 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000515 environment->HasUint32ValueAt(i),
516 &object_index,
517 &dematerialized_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000518 }
519}
520
521
danno@chromium.org59400602013-08-13 17:09:37 +0000522void LCodeGen::AddToTranslation(LEnvironment* environment,
523 Translation* translation,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000524 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000525 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000526 bool is_uint32,
527 int* object_index_pointer,
528 int* dematerialized_index_pointer) {
529 if (op == LEnvironment::materialization_marker()) {
530 int object_index = (*object_index_pointer)++;
531 if (environment->ObjectIsDuplicateAt(object_index)) {
532 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
533 translation->DuplicateObject(dupe_of);
534 return;
535 }
536 int object_length = environment->ObjectLengthAt(object_index);
537 if (environment->ObjectIsArgumentsAt(object_index)) {
538 translation->BeginArgumentsObject(object_length);
539 } else {
540 translation->BeginCapturedObject(object_length);
541 }
542 int dematerialized_index = *dematerialized_index_pointer;
543 int env_offset = environment->translation_size() + dematerialized_index;
544 *dematerialized_index_pointer += object_length;
545 for (int i = 0; i < object_length; ++i) {
546 LOperand* value = environment->values()->at(env_offset + i);
547 AddToTranslation(environment,
548 translation,
549 value,
550 environment->HasTaggedValueAt(env_offset + i),
551 environment->HasUint32ValueAt(env_offset + i),
552 object_index_pointer,
553 dematerialized_index_pointer);
554 }
555 return;
556 }
557
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000558 if (op->IsStackSlot()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000559 if (is_tagged) {
560 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000561 } else if (is_uint32) {
562 translation->StoreUint32StackSlot(op->index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000563 } else {
564 translation->StoreInt32StackSlot(op->index());
565 }
566 } else if (op->IsDoubleStackSlot()) {
567 translation->StoreDoubleStackSlot(op->index());
568 } else if (op->IsArgument()) {
569 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000570 int src_index = GetStackSlotCount() + op->index();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000571 translation->StoreStackSlot(src_index);
572 } else if (op->IsRegister()) {
573 Register reg = ToRegister(op);
574 if (is_tagged) {
575 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000576 } else if (is_uint32) {
577 translation->StoreUint32Register(reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000578 } else {
579 translation->StoreInt32Register(reg);
580 }
581 } else if (op->IsDoubleRegister()) {
582 XMMRegister reg = ToDoubleRegister(op);
583 translation->StoreDoubleRegister(reg);
584 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000585 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000586 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000587 translation->StoreLiteral(src_index);
588 } else {
589 UNREACHABLE();
590 }
591}
592
593
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000594void LCodeGen::CallCodeGeneric(Handle<Code> code,
595 RelocInfo::Mode mode,
596 LInstruction* instr,
597 SafepointMode safepoint_mode,
598 int argc) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000599 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000600 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000601 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000602 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000603
604 // Signal that we don't inline smi code before these stubs in the
605 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000606 if (code->kind() == Code::BINARY_OP_IC ||
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000607 code->kind() == Code::COMPARE_IC) {
608 __ nop();
609 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000610}
611
612
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000613void LCodeGen::CallCode(Handle<Code> code,
614 RelocInfo::Mode mode,
615 LInstruction* instr) {
616 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0);
617}
618
619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620void LCodeGen::CallRuntime(const Runtime::Function* function,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000621 int num_arguments,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000622 LInstruction* instr,
623 SaveFPRegsMode save_doubles) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000624 ASSERT(instr != NULL);
625 ASSERT(instr->HasPointerMap());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000626
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000627 __ CallRuntime(function, num_arguments, save_doubles);
628
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000629 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000630}
631
632
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000633void LCodeGen::LoadContextFromDeferred(LOperand* context) {
634 if (context->IsRegister()) {
635 if (!ToRegister(context).is(rsi)) {
636 __ movq(rsi, ToRegister(context));
637 }
638 } else if (context->IsStackSlot()) {
639 __ movq(rsi, ToOperand(context));
640 } else if (context->IsConstantOperand()) {
641 HConstant* constant =
642 chunk_->LookupConstant(LConstantOperand::cast(context));
643 __ Move(rsi, Handle<Object>::cast(constant->handle(isolate())));
644 } else {
645 UNREACHABLE();
646 }
647}
648
649
650
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000651void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
652 int argc,
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000653 LInstruction* instr,
654 LOperand* context) {
655 LoadContextFromDeferred(context);
656
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000657 __ CallRuntimeSaveDoubles(id);
658 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000659 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000660}
661
662
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000663void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
664 Safepoint::DeoptMode mode) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000665 if (!environment->HasBeenRegistered()) {
666 // Physical stack frame layout:
667 // -x ............. -4 0 ..................................... y
668 // [incoming arguments] [spill slots] [pushed outgoing arguments]
669
670 // Layout of the environment:
671 // 0 ..................................................... size-1
672 // [parameters] [locals] [expression stack including arguments]
673
674 // Layout of the translation:
675 // 0 ........................................................ size - 1 + 4
676 // [expression stack including arguments] [locals] [4 words] [parameters]
677 // |>------------ translation_size ------------<|
678
679 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000680 int jsframe_count = 0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000681 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
682 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000683 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000684 ++jsframe_count;
685 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000686 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000687 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000688 WriteTranslation(environment, &translation);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000689 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000690 int pc_offset = masm()->pc_offset();
691 environment->Register(deoptimization_index,
692 translation.index(),
693 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000694 deoptimizations_.Add(environment, environment->zone());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000695 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000696}
697
698
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000699void LCodeGen::DeoptimizeIf(Condition cc,
700 LEnvironment* environment,
701 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000702 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000703 ASSERT(environment->HasBeenRegistered());
704 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000705 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000706 Address entry =
707 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000708 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +0000709 Abort(kBailoutWasNotPrepared);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000710 return;
711 }
712
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000713 if (DeoptEveryNTimes()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000714 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
715 Label no_deopt;
716 __ pushfq();
717 __ push(rax);
718 Operand count_operand = masm()->ExternalOperand(count, kScratchRegister);
719 __ movl(rax, count_operand);
720 __ subl(rax, Immediate(1));
721 __ j(not_zero, &no_deopt, Label::kNear);
722 if (FLAG_trap_on_deopt) __ int3();
723 __ movl(rax, Immediate(FLAG_deopt_every_n_times));
724 __ movl(count_operand, rax);
725 __ pop(rax);
726 __ popfq();
727 ASSERT(frame_is_built_);
728 __ call(entry, RelocInfo::RUNTIME_ENTRY);
729 __ bind(&no_deopt);
730 __ movl(count_operand, rax);
731 __ pop(rax);
732 __ popfq();
733 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000734
danno@chromium.org59400602013-08-13 17:09:37 +0000735 if (info()->ShouldTrapOnDeopt()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000736 Label done;
737 if (cc != no_condition) {
738 __ j(NegateCondition(cc), &done, Label::kNear);
739 }
740 __ int3();
741 __ bind(&done);
742 }
743
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000744 ASSERT(info()->IsStub() || frame_is_built_);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000745 // Go through jump table if we need to handle condition, build frame, or
746 // restore caller doubles.
747 if (cc == no_condition && frame_is_built_ &&
748 !info()->saves_caller_doubles()) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000749 __ call(entry, RelocInfo::RUNTIME_ENTRY);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000750 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000751 // We often have several deopts to the same entry, reuse the last
752 // jump entry if this is the case.
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000753 if (jump_table_.is_empty() ||
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000754 jump_table_.last().address != entry ||
755 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000756 jump_table_.last().bailout_type != bailout_type) {
757 Deoptimizer::JumpTableEntry table_entry(entry,
758 bailout_type,
759 !frame_is_built_);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000760 jump_table_.Add(table_entry, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000761 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000762 if (cc == no_condition) {
763 __ jmp(&jump_table_.last().label);
764 } else {
765 __ j(cc, &jump_table_.last().label);
766 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000767 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000768}
769
770
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000771void LCodeGen::DeoptimizeIf(Condition cc,
772 LEnvironment* environment) {
773 Deoptimizer::BailoutType bailout_type = info()->IsStub()
774 ? Deoptimizer::LAZY
775 : Deoptimizer::EAGER;
776 DeoptimizeIf(cc, environment, bailout_type);
777}
778
779
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000780void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
781 int length = deoptimizations_.length();
782 if (length == 0) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000783 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000784 factory()->NewDeoptimizationInputData(length, TENURED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000785
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000786 Handle<ByteArray> translations =
787 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000788 data->SetTranslationByteArray(*translations);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000789 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
790
791 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000792 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000793 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000794 for (int i = 0; i < deoptimization_literals_.length(); i++) {
795 literals->set(i, *deoptimization_literals_[i]);
796 }
797 data->SetLiteralArray(*literals);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000798 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000799
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000800 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000801 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
802
803 // Populate the deoptimization entries.
804 for (int i = 0; i < length; i++) {
805 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000806 data->SetAstId(i, env->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000807 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
808 data->SetArgumentsStackHeight(i,
809 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000810 data->SetPc(i, Smi::FromInt(env->pc_offset()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000811 }
812 code->set_deoptimization_data(*data);
813}
814
815
816int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
817 int result = deoptimization_literals_.length();
818 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
819 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
820 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000821 deoptimization_literals_.Add(literal, zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000822 return result;
823}
824
825
826void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
827 ASSERT(deoptimization_literals_.length() == 0);
828
829 const ZoneList<Handle<JSFunction> >* inlined_closures =
830 chunk()->inlined_closures();
831
832 for (int i = 0, length = inlined_closures->length();
833 i < length;
834 i++) {
835 DefineDeoptimizationLiteral(inlined_closures->at(i));
836 }
837
838 inlined_function_count_ = deoptimization_literals_.length();
839}
840
841
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000842void LCodeGen::RecordSafepointWithLazyDeopt(
843 LInstruction* instr, SafepointMode safepoint_mode, int argc) {
844 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
845 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
846 } else {
847 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
848 RecordSafepointWithRegisters(
849 instr->pointer_map(), argc, Safepoint::kLazyDeopt);
850 }
851}
852
853
ager@chromium.org378b34e2011-01-28 08:04:38 +0000854void LCodeGen::RecordSafepoint(
855 LPointerMap* pointers,
856 Safepoint::Kind kind,
857 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000858 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000859 ASSERT(kind == expected_safepoint_kind_);
860
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000861 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000862
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000863 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000864 kind, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000865 for (int i = 0; i < operands->length(); i++) {
866 LOperand* pointer = operands->at(i);
867 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000868 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000869 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000870 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000871 }
872 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000873}
874
875
876void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000877 Safepoint::DeoptMode deopt_mode) {
878 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000879}
880
881
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000882void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000883 LPointerMap empty_pointers(zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000884 RecordSafepoint(&empty_pointers, deopt_mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000885}
886
887
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000888void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
889 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000890 Safepoint::DeoptMode deopt_mode) {
891 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000892}
893
894
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000895void LCodeGen::RecordAndWritePosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000896 if (position == RelocInfo::kNoPosition) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000897 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000898 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +0000899}
900
901
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000902static const char* LabelType(LLabel* label) {
903 if (label->is_loop_header()) return " (loop header)";
904 if (label->is_osr_entry()) return " (OSR entry)";
905 return "";
906}
907
908
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000909void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000910 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
911 current_instruction_,
912 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000913 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000914 LabelType(label));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000915 __ bind(label->label());
916 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000917 DoGap(label);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000918}
919
920
921void LCodeGen::DoParallelMove(LParallelMove* move) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000922 resolver_.Resolve(move);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000923}
924
925
926void LCodeGen::DoGap(LGap* gap) {
927 for (int i = LGap::FIRST_INNER_POSITION;
928 i <= LGap::LAST_INNER_POSITION;
929 i++) {
930 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
931 LParallelMove* move = gap->GetParallelMove(inner_pos);
932 if (move != NULL) DoParallelMove(move);
933 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000934}
935
936
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000937void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
938 DoGap(instr);
939}
940
941
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000942void LCodeGen::DoParameter(LParameter* instr) {
943 // Nothing to do.
944}
945
946
947void LCodeGen::DoCallStub(LCallStub* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000948 ASSERT(ToRegister(instr->context()).is(rsi));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000949 ASSERT(ToRegister(instr->result()).is(rax));
950 switch (instr->hydrogen()->major_key()) {
951 case CodeStub::RegExpConstructResult: {
952 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000953 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000954 break;
955 }
956 case CodeStub::RegExpExec: {
957 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000958 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 break;
960 }
961 case CodeStub::SubString: {
962 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000963 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000964 break;
965 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000966 case CodeStub::StringCompare: {
967 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000968 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000969 break;
970 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000971 default:
972 UNREACHABLE();
973 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000974}
975
976
977void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000978 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000979}
980
981
982void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000983 HMod* hmod = instr->hydrogen();
984 HValue* left = hmod->left();
985 HValue* right = hmod->right();
986 if (hmod->HasPowerOf2Divisor()) {
987 // TODO(svenpanne) We should really do the strength reduction on the
988 // Hydrogen level.
989 Register left_reg = ToRegister(instr->left());
990 ASSERT(left_reg.is(ToRegister(instr->result())));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000991
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000992 // Note: The code below even works when right contains kMinInt.
993 int32_t divisor = Abs(right->GetInteger32Constant());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000994
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000995 Label left_is_not_negative, done;
996 if (left->CanBeNegative()) {
997 __ testl(left_reg, left_reg);
998 __ j(not_sign, &left_is_not_negative, Label::kNear);
999 __ negl(left_reg);
1000 __ andl(left_reg, Immediate(divisor - 1));
1001 __ negl(left_reg);
1002 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1003 DeoptimizeIf(zero, instr->environment());
1004 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001005 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001006 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001007
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001008 __ bind(&left_is_not_negative);
1009 __ andl(left_reg, Immediate(divisor - 1));
1010 __ bind(&done);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001011 } else {
1012 Register left_reg = ToRegister(instr->left());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001013 ASSERT(left_reg.is(rax));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001014 Register right_reg = ToRegister(instr->right());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001015 ASSERT(!right_reg.is(rax));
1016 ASSERT(!right_reg.is(rdx));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001017 Register result_reg = ToRegister(instr->result());
1018 ASSERT(result_reg.is(rdx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001019
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001020 Label done;
1021 // Check for x % 0, idiv would signal a divide error. We have to
1022 // deopt in this case because we can't return a NaN.
1023 if (right->CanBeZero()) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001024 __ testl(right_reg, right_reg);
1025 DeoptimizeIf(zero, instr->environment());
1026 }
1027
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001028 // Check for kMinInt % -1, idiv would signal a divide error. We
1029 // have to deopt if we care about -0, because we can't return that.
1030 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1031 Label no_overflow_possible;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001032 __ cmpl(left_reg, Immediate(kMinInt));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001033 __ j(not_zero, &no_overflow_possible, Label::kNear);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001034 __ cmpl(right_reg, Immediate(-1));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001035 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1036 DeoptimizeIf(equal, instr->environment());
1037 } else {
1038 __ j(not_equal, &no_overflow_possible, Label::kNear);
1039 __ Set(result_reg, 0);
1040 __ jmp(&done, Label::kNear);
1041 }
1042 __ bind(&no_overflow_possible);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001043 }
1044
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001045 // Sign extend dividend in eax into edx:eax, since we are using only the low
1046 // 32 bits of the values.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001047 __ cdq();
1048
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001049 // If we care about -0, test if the dividend is <0 and the result is 0.
1050 if (left->CanBeNegative() &&
1051 hmod->CanBeZero() &&
1052 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001053 Label positive_left;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001054 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001055 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001056 __ idivl(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001057 __ testl(result_reg, result_reg);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001058 DeoptimizeIf(zero, instr->environment());
1059 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001060 __ bind(&positive_left);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001061 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001062 __ idivl(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001063 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001064 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001065}
1066
1067
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001068void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001069 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001070
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001071 const Register dividend = ToRegister(instr->left());
1072 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001073 const Register result = ToRegister(instr->result());
1074
1075 switch (divisor) {
1076 case 0:
1077 DeoptimizeIf(no_condition, instr->environment());
1078 return;
1079
1080 case 1:
1081 if (!result.is(dividend)) {
1082 __ movl(result, dividend);
1083 }
1084 return;
1085
1086 case -1:
1087 if (!result.is(dividend)) {
1088 __ movl(result, dividend);
1089 }
1090 __ negl(result);
1091 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1092 DeoptimizeIf(zero, instr->environment());
1093 }
1094 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1095 DeoptimizeIf(overflow, instr->environment());
1096 }
1097 return;
1098 }
1099
1100 uint32_t divisor_abs = abs(divisor);
1101 if (IsPowerOf2(divisor_abs)) {
1102 int32_t power = WhichPowerOf2(divisor_abs);
1103 if (divisor < 0) {
1104 __ movsxlq(result, dividend);
1105 __ neg(result);
1106 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1107 DeoptimizeIf(zero, instr->environment());
1108 }
1109 __ sar(result, Immediate(power));
1110 } else {
1111 if (!result.is(dividend)) {
1112 __ movl(result, dividend);
1113 }
1114 __ sarl(result, Immediate(power));
1115 }
1116 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001117 Register reg1 = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001118 Register reg2 = ToRegister(instr->result());
1119
1120 // Find b which: 2^b < divisor_abs < 2^(b+1).
1121 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1122 unsigned shift = 32 + b; // Precision +1bit (effectively).
1123 double multiplier_f =
1124 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1125 int64_t multiplier;
1126 if (multiplier_f - floor(multiplier_f) < 0.5) {
1127 multiplier = static_cast<int64_t>(floor(multiplier_f));
1128 } else {
1129 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1130 }
1131 // The multiplier is a uint32.
1132 ASSERT(multiplier > 0 &&
1133 multiplier < (static_cast<int64_t>(1) << 32));
1134 // The multiply is int64, so sign-extend to r64.
1135 __ movsxlq(reg1, dividend);
1136 if (divisor < 0 &&
1137 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1138 __ neg(reg1);
1139 DeoptimizeIf(zero, instr->environment());
1140 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001141 __ Set(reg2, multiplier);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001142 // Result just fit in r64, because it's int32 * uint32.
1143 __ imul(reg2, reg1);
1144
1145 __ addq(reg2, Immediate(1 << 30));
1146 __ sar(reg2, Immediate(shift));
1147 }
1148}
1149
1150
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001151void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001152 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001153 Register dividend = ToRegister(instr->left());
1154 int32_t divisor =
1155 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1156 int32_t test_value = 0;
1157 int32_t power = 0;
1158
1159 if (divisor > 0) {
1160 test_value = divisor - 1;
1161 power = WhichPowerOf2(divisor);
1162 } else {
1163 // Check for (0 / -x) that will produce negative zero.
1164 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1165 __ testl(dividend, dividend);
1166 DeoptimizeIf(zero, instr->environment());
1167 }
1168 // Check for (kMinInt / -1).
1169 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1170 __ cmpl(dividend, Immediate(kMinInt));
1171 DeoptimizeIf(zero, instr->environment());
1172 }
1173 test_value = - divisor - 1;
1174 power = WhichPowerOf2(-divisor);
1175 }
1176
1177 if (test_value != 0) {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001178 if (instr->hydrogen()->CheckFlag(
1179 HInstruction::kAllUsesTruncatingToInt32)) {
1180 Label done, negative;
1181 __ cmpl(dividend, Immediate(0));
1182 __ j(less, &negative, Label::kNear);
1183 __ sarl(dividend, Immediate(power));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001184 if (divisor < 0) __ negl(dividend);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001185 __ jmp(&done, Label::kNear);
1186
1187 __ bind(&negative);
1188 __ negl(dividend);
1189 __ sarl(dividend, Immediate(power));
1190 if (divisor > 0) __ negl(dividend);
1191 __ bind(&done);
1192 return; // Don't fall through to "__ neg" below.
1193 } else {
1194 // Deoptimize if remainder is not 0.
1195 __ testl(dividend, Immediate(test_value));
1196 DeoptimizeIf(not_zero, instr->environment());
1197 __ sarl(dividend, Immediate(power));
1198 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001199 }
1200
1201 if (divisor < 0) __ negl(dividend);
1202
1203 return;
1204 }
1205
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001206 LOperand* right = instr->right();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001207 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001208 ASSERT(ToRegister(instr->left()).is(rax));
1209 ASSERT(!ToRegister(instr->right()).is(rax));
1210 ASSERT(!ToRegister(instr->right()).is(rdx));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001211
1212 Register left_reg = rax;
1213
1214 // Check for x / 0.
1215 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001216 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001217 __ testl(right_reg, right_reg);
1218 DeoptimizeIf(zero, instr->environment());
1219 }
1220
1221 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001222 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001223 Label left_not_zero;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001224 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001225 __ j(not_zero, &left_not_zero, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001226 __ testl(right_reg, right_reg);
1227 DeoptimizeIf(sign, instr->environment());
1228 __ bind(&left_not_zero);
1229 }
1230
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001231 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001232 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001233 Label left_not_min_int;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001234 __ cmpl(left_reg, Immediate(kMinInt));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001235 __ j(not_zero, &left_not_min_int, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001236 __ cmpl(right_reg, Immediate(-1));
1237 DeoptimizeIf(zero, instr->environment());
1238 __ bind(&left_not_min_int);
1239 }
1240
1241 // Sign extend to rdx.
1242 __ cdq();
1243 __ idivl(right_reg);
1244
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001245 if (instr->is_flooring()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001246 Label done;
1247 __ testl(rdx, rdx);
1248 __ j(zero, &done, Label::kNear);
1249 __ xorl(rdx, right_reg);
1250 __ sarl(rdx, Immediate(31));
1251 __ addl(rax, rdx);
1252 __ bind(&done);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001253 } else if (!instr->hydrogen()->CheckFlag(
1254 HInstruction::kAllUsesTruncatingToInt32)) {
1255 // Deoptimize if remainder is not 0.
1256 __ testl(rdx, rdx);
1257 DeoptimizeIf(not_zero, instr->environment());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001258 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001259}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001260
1261
1262void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001263 Register left = ToRegister(instr->left());
1264 LOperand* right = instr->right();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001265
1266 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001267 if (instr->hydrogen_value()->representation().IsSmi()) {
1268 __ movq(kScratchRegister, left);
1269 } else {
1270 __ movl(kScratchRegister, left);
1271 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001272 }
1273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 bool can_overflow =
1275 instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001276 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001277 int32_t right_value = ToInteger32(LConstantOperand::cast(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 if (right_value == -1) {
1279 __ negl(left);
1280 } else if (right_value == 0) {
1281 __ xorl(left, left);
1282 } else if (right_value == 2) {
1283 __ addl(left, left);
1284 } else if (!can_overflow) {
1285 // If the multiplication is known to not overflow, we
1286 // can use operations that don't set the overflow flag
1287 // correctly.
1288 switch (right_value) {
1289 case 1:
1290 // Do nothing.
1291 break;
1292 case 3:
1293 __ leal(left, Operand(left, left, times_2, 0));
1294 break;
1295 case 4:
1296 __ shll(left, Immediate(2));
1297 break;
1298 case 5:
1299 __ leal(left, Operand(left, left, times_4, 0));
1300 break;
1301 case 8:
1302 __ shll(left, Immediate(3));
1303 break;
1304 case 9:
1305 __ leal(left, Operand(left, left, times_8, 0));
1306 break;
1307 case 16:
1308 __ shll(left, Immediate(4));
1309 break;
1310 default:
1311 __ imull(left, left, Immediate(right_value));
1312 break;
1313 }
1314 } else {
1315 __ imull(left, left, Immediate(right_value));
1316 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001317 } else if (right->IsStackSlot()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001318 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001319 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001320 __ imul(left, ToOperand(right));
1321 } else {
1322 __ imull(left, ToOperand(right));
1323 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001324 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001325 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001326 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001327 __ imul(left, ToRegister(right));
1328 } else {
1329 __ imull(left, ToRegister(right));
1330 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001331 }
1332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001333 if (can_overflow) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001334 DeoptimizeIf(overflow, instr->environment());
1335 }
1336
1337 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1338 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001339 Label done;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001340 if (instr->hydrogen_value()->representation().IsSmi()) {
1341 __ testq(left, left);
1342 } else {
1343 __ testl(left, left);
1344 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001345 __ j(not_zero, &done, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001346 if (right->IsConstantOperand()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001347 // Constant can't be represented as Smi due to immediate size limit.
1348 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001349 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001350 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001351 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1352 __ cmpl(kScratchRegister, Immediate(0));
1353 DeoptimizeIf(less, instr->environment());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001354 }
1355 } else if (right->IsStackSlot()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001356 if (instr->hydrogen_value()->representation().IsSmi()) {
1357 __ or_(kScratchRegister, ToOperand(right));
1358 } else {
1359 __ orl(kScratchRegister, ToOperand(right));
1360 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001361 DeoptimizeIf(sign, instr->environment());
1362 } else {
1363 // Test the non-zero operand for negative sign.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001364 if (instr->hydrogen_value()->representation().IsSmi()) {
1365 __ or_(kScratchRegister, ToRegister(right));
1366 } else {
1367 __ orl(kScratchRegister, ToRegister(right));
1368 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001369 DeoptimizeIf(sign, instr->environment());
1370 }
1371 __ bind(&done);
1372 }
1373}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001374
1375
1376void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001377 LOperand* left = instr->left();
1378 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001379 ASSERT(left->Equals(instr->result()));
1380 ASSERT(left->IsRegister());
1381
1382 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001383 int32_t right_operand = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001384 switch (instr->op()) {
1385 case Token::BIT_AND:
1386 __ andl(ToRegister(left), Immediate(right_operand));
1387 break;
1388 case Token::BIT_OR:
1389 __ orl(ToRegister(left), Immediate(right_operand));
1390 break;
1391 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001392 if (right_operand == int32_t(~0)) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001393 __ notl(ToRegister(left));
danno@chromium.org59400602013-08-13 17:09:37 +00001394 } else {
1395 __ xorl(ToRegister(left), Immediate(right_operand));
1396 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001397 break;
1398 default:
1399 UNREACHABLE();
1400 break;
1401 }
1402 } else if (right->IsStackSlot()) {
1403 switch (instr->op()) {
1404 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001405 __ and_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001406 break;
1407 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001408 __ or_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001409 break;
1410 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001411 __ xor_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001412 break;
1413 default:
1414 UNREACHABLE();
1415 break;
1416 }
1417 } else {
1418 ASSERT(right->IsRegister());
1419 switch (instr->op()) {
1420 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001421 __ and_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001422 break;
1423 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001424 __ or_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001425 break;
1426 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001427 __ xor_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001428 break;
1429 default:
1430 UNREACHABLE();
1431 break;
1432 }
1433 }
1434}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001435
1436
1437void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001438 LOperand* left = instr->left();
1439 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001440 ASSERT(left->Equals(instr->result()));
1441 ASSERT(left->IsRegister());
1442 if (right->IsRegister()) {
1443 ASSERT(ToRegister(right).is(rcx));
1444
1445 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001446 case Token::ROR:
1447 __ rorl_cl(ToRegister(left));
1448 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001449 case Token::SAR:
1450 __ sarl_cl(ToRegister(left));
1451 break;
1452 case Token::SHR:
1453 __ shrl_cl(ToRegister(left));
1454 if (instr->can_deopt()) {
1455 __ testl(ToRegister(left), ToRegister(left));
1456 DeoptimizeIf(negative, instr->environment());
1457 }
1458 break;
1459 case Token::SHL:
1460 __ shll_cl(ToRegister(left));
1461 break;
1462 default:
1463 UNREACHABLE();
1464 break;
1465 }
1466 } else {
danno@chromium.org59400602013-08-13 17:09:37 +00001467 int32_t value = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001468 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1469 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001470 case Token::ROR:
1471 if (shift_count != 0) {
1472 __ rorl(ToRegister(left), Immediate(shift_count));
1473 }
1474 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001475 case Token::SAR:
1476 if (shift_count != 0) {
1477 __ sarl(ToRegister(left), Immediate(shift_count));
1478 }
1479 break;
1480 case Token::SHR:
1481 if (shift_count == 0 && instr->can_deopt()) {
1482 __ testl(ToRegister(left), ToRegister(left));
1483 DeoptimizeIf(negative, instr->environment());
1484 } else {
1485 __ shrl(ToRegister(left), Immediate(shift_count));
1486 }
1487 break;
1488 case Token::SHL:
1489 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001490 if (instr->hydrogen_value()->representation().IsSmi()) {
1491 __ shl(ToRegister(left), Immediate(shift_count));
1492 } else {
1493 __ shll(ToRegister(left), Immediate(shift_count));
1494 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001495 }
1496 break;
1497 default:
1498 UNREACHABLE();
1499 break;
1500 }
1501 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001502}
1503
1504
1505void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001506 LOperand* left = instr->left();
1507 LOperand* right = instr->right();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001508 ASSERT(left->Equals(instr->result()));
1509
1510 if (right->IsConstantOperand()) {
1511 __ subl(ToRegister(left),
1512 Immediate(ToInteger32(LConstantOperand::cast(right))));
1513 } else if (right->IsRegister()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001514 if (instr->hydrogen_value()->representation().IsSmi()) {
1515 __ subq(ToRegister(left), ToRegister(right));
1516 } else {
1517 __ subl(ToRegister(left), ToRegister(right));
1518 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001519 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001520 if (instr->hydrogen_value()->representation().IsSmi()) {
1521 __ subq(ToRegister(left), ToOperand(right));
1522 } else {
1523 __ subl(ToRegister(left), ToOperand(right));
1524 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001525 }
1526
1527 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1528 DeoptimizeIf(overflow, instr->environment());
1529 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001530}
1531
1532
1533void LCodeGen::DoConstantI(LConstantI* instr) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001534 __ Set(ToRegister(instr->result()), instr->value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001535}
1536
1537
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001538void LCodeGen::DoConstantS(LConstantS* instr) {
1539 __ Move(ToRegister(instr->result()), instr->value());
1540}
1541
1542
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001543void LCodeGen::DoConstantD(LConstantD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001544 ASSERT(instr->result()->IsDoubleRegister());
1545 XMMRegister res = ToDoubleRegister(instr->result());
1546 double v = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001547 uint64_t int_val = BitCast<uint64_t, double>(v);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001548 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1549 // do so if the constant is -0.0.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001550 if (int_val == 0) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001551 __ xorps(res, res);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001552 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001553 Register tmp = ToRegister(instr->temp());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001554 __ Set(tmp, int_val);
1555 __ movq(res, tmp);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001556 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001557}
1558
1559
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001560void LCodeGen::DoConstantE(LConstantE* instr) {
1561 __ LoadAddress(ToRegister(instr->result()), instr->value());
1562}
1563
1564
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001565void LCodeGen::DoConstantT(LConstantT* instr) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001566 Handle<Object> value = instr->value(isolate());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001567 __ Move(ToRegister(instr->result()), value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001568}
1569
1570
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001571void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1572 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001573 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001574 __ EnumLength(result, map);
1575}
1576
1577
whesse@chromium.org7b260152011-06-20 15:33:18 +00001578void LCodeGen::DoElementsKind(LElementsKind* instr) {
1579 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001580 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001581
1582 // Load map into |result|.
1583 __ movq(result, FieldOperand(input, HeapObject::kMapOffset));
1584 // Load the map's "bit field 2" into |result|. We only need the first byte.
1585 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset));
1586 // Retrieve elements_kind from bit field 2.
1587 __ and_(result, Immediate(Map::kElementsKindMask));
1588 __ shr(result, Immediate(Map::kElementsKindShift));
1589}
1590
1591
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001592void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001593 Register input = ToRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001594 Register result = ToRegister(instr->result());
1595 ASSERT(input.is(result));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001596 Label done;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001597
1598 if (!instr->hydrogen()->value()->IsHeapObject()) {
1599 // If the object is a smi return the object.
1600 __ JumpIfSmi(input, &done, Label::kNear);
1601 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001602
1603 // If the object is not a value type, return the object.
1604 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001605 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001606 __ movq(result, FieldOperand(input, JSValue::kValueOffset));
1607
1608 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001609}
1610
1611
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001612void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001613 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001614 Register result = ToRegister(instr->result());
1615 Smi* index = instr->index();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001616 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001617 ASSERT(object.is(result));
1618 ASSERT(object.is(rax));
1619
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001620 Condition cc = masm()->CheckSmi(object);
1621 DeoptimizeIf(cc, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001622 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001623 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001624
1625 if (index->value() == 0) {
1626 __ movq(result, FieldOperand(object, JSDate::kValueOffset));
1627 } else {
1628 if (index->value() < JSDate::kFirstUncachedField) {
1629 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001630 Operand stamp_operand = __ ExternalOperand(stamp);
1631 __ movq(kScratchRegister, stamp_operand);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001632 __ cmpq(kScratchRegister, FieldOperand(object,
1633 JSDate::kCacheStampOffset));
1634 __ j(not_equal, &runtime, Label::kNear);
1635 __ movq(result, FieldOperand(object, JSDate::kValueOffset +
1636 kPointerSize * index->value()));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001637 __ jmp(&done, Label::kNear);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001638 }
1639 __ bind(&runtime);
1640 __ PrepareCallCFunction(2);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001641 __ movq(arg_reg_1, object);
1642 __ movq(arg_reg_2, index, RelocInfo::NONE64);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001643 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001644 __ bind(&done);
1645 }
1646}
1647
1648
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001649Operand LCodeGen::BuildSeqStringOperand(Register string,
1650 LOperand* index,
1651 String::Encoding encoding) {
1652 if (index->IsConstantOperand()) {
1653 int offset = ToInteger32(LConstantOperand::cast(index));
1654 if (encoding == String::TWO_BYTE_ENCODING) {
1655 offset *= kUC16Size;
1656 }
1657 STATIC_ASSERT(kCharSize == 1);
1658 return FieldOperand(string, SeqString::kHeaderSize + offset);
1659 }
1660 return FieldOperand(
1661 string, ToRegister(index),
1662 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
1663 SeqString::kHeaderSize);
1664}
1665
1666
1667void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1668 String::Encoding encoding = instr->hydrogen()->encoding();
1669 Register result = ToRegister(instr->result());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001670 Register string = ToRegister(instr->string());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001671
1672 if (FLAG_debug_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001673 __ push(string);
1674 __ movq(string, FieldOperand(string, HeapObject::kMapOffset));
1675 __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001676
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001677 __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001678 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1679 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001680 __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
1681 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00001682 __ Check(equal, kUnexpectedStringType);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001683 __ pop(string);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001684 }
1685
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001686 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001687 if (encoding == String::ONE_BYTE_ENCODING) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001688 __ movzxbl(result, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001689 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001690 __ movzxwl(result, operand);
1691 }
1692}
1693
1694
1695void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1696 String::Encoding encoding = instr->hydrogen()->encoding();
1697 Register string = ToRegister(instr->string());
1698
1699 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001700 Register value = ToRegister(instr->value());
1701 Register index = ToRegister(instr->index());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001702 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1703 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001704 int encoding_mask =
1705 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1706 ? one_byte_seq_type : two_byte_seq_type;
1707 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001708 }
1709
1710 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1711 if (instr->value()->IsConstantOperand()) {
1712 int value = ToInteger32(LConstantOperand::cast(instr->value()));
1713 ASSERT_LE(0, value);
1714 if (encoding == String::ONE_BYTE_ENCODING) {
1715 ASSERT_LE(value, String::kMaxOneByteCharCode);
1716 __ movb(operand, Immediate(value));
1717 } else {
1718 ASSERT_LE(value, String::kMaxUtf16CodeUnit);
1719 __ movw(operand, Immediate(value));
1720 }
1721 } else {
1722 Register value = ToRegister(instr->value());
1723 if (encoding == String::ONE_BYTE_ENCODING) {
1724 __ movb(operand, value);
1725 } else {
1726 __ movw(operand, value);
1727 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001728 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001729}
1730
1731
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001732void LCodeGen::DoThrow(LThrow* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001733 __ push(ToRegister(instr->value()));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001734 ASSERT(ToRegister(instr->context()).is(rsi));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001735 CallRuntime(Runtime::kThrow, 1, instr);
1736
1737 if (FLAG_debug_code) {
1738 Comment("Unreachable code.");
1739 __ int3();
1740 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001741}
1742
1743
1744void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001745 LOperand* left = instr->left();
1746 LOperand* right = instr->right();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001747
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001748 Representation target_rep = instr->hydrogen()->representation();
1749 bool is_q = target_rep.IsSmi() || target_rep.IsExternal();
1750
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001751 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1752 if (right->IsConstantOperand()) {
1753 int32_t offset = ToInteger32(LConstantOperand::cast(right));
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001754 if (is_q) {
1755 __ lea(ToRegister(instr->result()),
1756 MemOperand(ToRegister(left), offset));
1757 } else {
1758 __ leal(ToRegister(instr->result()),
1759 MemOperand(ToRegister(left), offset));
1760 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001761 } else {
1762 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001763 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001764 __ lea(ToRegister(instr->result()), address);
1765 } else {
1766 __ leal(ToRegister(instr->result()), address);
1767 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001768 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001769 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001770 if (right->IsConstantOperand()) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001771 if (is_q) {
1772 __ addq(ToRegister(left),
1773 Immediate(ToInteger32(LConstantOperand::cast(right))));
1774 } else {
1775 __ addl(ToRegister(left),
1776 Immediate(ToInteger32(LConstantOperand::cast(right))));
1777 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001778 } else if (right->IsRegister()) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001779 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001780 __ addq(ToRegister(left), ToRegister(right));
1781 } else {
1782 __ addl(ToRegister(left), ToRegister(right));
1783 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001784 } else {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001785 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001786 __ addq(ToRegister(left), ToOperand(right));
1787 } else {
1788 __ addl(ToRegister(left), ToOperand(right));
1789 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001790 }
1791 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1792 DeoptimizeIf(overflow, instr->environment());
1793 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001794 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001795}
1796
1797
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001798void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001799 LOperand* left = instr->left();
1800 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001801 ASSERT(left->Equals(instr->result()));
1802 HMathMinMax::Operation operation = instr->hydrogen()->operation();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001803 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001804 Label return_left;
1805 Condition condition = (operation == HMathMinMax::kMathMin)
1806 ? less_equal
1807 : greater_equal;
1808 Register left_reg = ToRegister(left);
1809 if (right->IsConstantOperand()) {
1810 Immediate right_imm =
1811 Immediate(ToInteger32(LConstantOperand::cast(right)));
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001812 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
ulan@chromium.org4121f232012-12-27 15:57:11 +00001813 __ cmpl(left_reg, right_imm);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001814 __ j(condition, &return_left, Label::kNear);
1815 __ movq(left_reg, right_imm);
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001816 } else if (right->IsRegister()) {
1817 Register right_reg = ToRegister(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001818 if (instr->hydrogen_value()->representation().IsSmi()) {
1819 __ cmpq(left_reg, right_reg);
1820 } else {
1821 __ cmpl(left_reg, right_reg);
1822 }
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001823 __ j(condition, &return_left, Label::kNear);
1824 __ movq(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001825 } else {
1826 Operand right_op = ToOperand(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001827 if (instr->hydrogen_value()->representation().IsSmi()) {
1828 __ cmpq(left_reg, right_op);
1829 } else {
1830 __ cmpl(left_reg, right_op);
1831 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001832 __ j(condition, &return_left, Label::kNear);
1833 __ movq(left_reg, right_op);
1834 }
1835 __ bind(&return_left);
1836 } else {
1837 ASSERT(instr->hydrogen()->representation().IsDouble());
1838 Label check_nan_left, check_zero, return_left, return_right;
1839 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1840 XMMRegister left_reg = ToDoubleRegister(left);
1841 XMMRegister right_reg = ToDoubleRegister(right);
1842 __ ucomisd(left_reg, right_reg);
1843 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1844 __ j(equal, &check_zero, Label::kNear); // left == right.
1845 __ j(condition, &return_left, Label::kNear);
1846 __ jmp(&return_right, Label::kNear);
1847
1848 __ bind(&check_zero);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001849 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001850 __ xorps(xmm_scratch, xmm_scratch);
1851 __ ucomisd(left_reg, xmm_scratch);
1852 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1853 // At this point, both left and right are either 0 or -0.
1854 if (operation == HMathMinMax::kMathMin) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001855 __ orps(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001856 } else {
1857 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1858 __ addsd(left_reg, right_reg);
1859 }
1860 __ jmp(&return_left, Label::kNear);
1861
1862 __ bind(&check_nan_left);
1863 __ ucomisd(left_reg, left_reg); // NaN check.
1864 __ j(parity_even, &return_left, Label::kNear);
1865 __ bind(&return_right);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001866 __ movaps(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001867
1868 __ bind(&return_left);
1869 }
1870}
1871
1872
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001873void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001874 XMMRegister left = ToDoubleRegister(instr->left());
1875 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001876 XMMRegister result = ToDoubleRegister(instr->result());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001877 // All operations except MOD are computed in-place.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001878 ASSERT(instr->op() == Token::MOD || left.is(result));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001879 switch (instr->op()) {
1880 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001881 __ addsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001882 break;
1883 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001884 __ subsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001885 break;
1886 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001887 __ mulsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001888 break;
1889 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001890 __ divsd(left, right);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001891 // Don't delete this mov. It may improve performance on some CPUs,
1892 // when there is a mulsd depending on the result
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001893 __ movaps(left, left);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001894 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001895 case Token::MOD: {
1896 XMMRegister xmm_scratch = double_scratch0();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001897 __ PrepareCallCFunction(2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001898 __ movaps(xmm_scratch, left);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001899 ASSERT(right.is(xmm1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001901 ExternalReference::mod_two_doubles_operation(isolate()), 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001902 __ movaps(result, xmm_scratch);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001903 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001904 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001905 default:
1906 UNREACHABLE();
1907 break;
1908 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001909}
1910
1911
1912void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001913 ASSERT(ToRegister(instr->context()).is(rsi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001914 ASSERT(ToRegister(instr->left()).is(rdx));
1915 ASSERT(ToRegister(instr->right()).is(rax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001916 ASSERT(ToRegister(instr->result()).is(rax));
1917
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001918 BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001919 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001920 __ nop(); // Signals no inlined code.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001921}
1922
1923
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001924template<class InstrType>
1925void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001926 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001927 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001928
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001929 int next_block = GetNextEmittedBlock();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001930
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001931 if (right_block == left_block || cc == no_condition) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001932 EmitGoto(left_block);
1933 } else if (left_block == next_block) {
1934 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1935 } else if (right_block == next_block) {
1936 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1937 } else {
1938 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1939 if (cc != always) {
1940 __ jmp(chunk_->GetAssemblyLabel(right_block));
1941 }
1942 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001943}
1944
1945
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00001946template<class InstrType>
1947void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
1948 int false_block = instr->FalseDestination(chunk_);
1949 __ j(cc, chunk_->GetAssemblyLabel(false_block));
1950}
1951
1952
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001953void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1954 __ int3();
1955}
1956
1957
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001958void LCodeGen::DoBranch(LBranch* instr) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001959 Representation r = instr->hydrogen()->value()->representation();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001960 if (r.IsInteger32()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001961 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001962 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001963 __ testl(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001964 EmitBranch(instr, not_zero);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001965 } else if (r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001966 ASSERT(!info()->IsStub());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001967 Register reg = ToRegister(instr->value());
1968 __ testq(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001969 EmitBranch(instr, not_zero);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001970 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001971 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001972 XMMRegister reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001973 XMMRegister xmm_scratch = double_scratch0();
1974 __ xorps(xmm_scratch, xmm_scratch);
1975 __ ucomisd(reg, xmm_scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001976 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001977 } else {
1978 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001979 Register reg = ToRegister(instr->value());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001980 HType type = instr->hydrogen()->value()->type();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001981 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001982 ASSERT(!info()->IsStub());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001983 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001984 EmitBranch(instr, equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001985 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001986 ASSERT(!info()->IsStub());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001987 __ SmiCompare(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001988 EmitBranch(instr, not_equal);
1989 } else if (type.IsJSArray()) {
1990 ASSERT(!info()->IsStub());
1991 EmitBranch(instr, no_condition);
1992 } else if (type.IsHeapNumber()) {
1993 ASSERT(!info()->IsStub());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001994 XMMRegister xmm_scratch = double_scratch0();
1995 __ xorps(xmm_scratch, xmm_scratch);
1996 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001997 EmitBranch(instr, not_equal);
1998 } else if (type.IsString()) {
1999 ASSERT(!info()->IsStub());
2000 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
2001 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002002 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002003 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2004 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002005 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002006
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002007 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2008 // undefined -> false.
2009 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002010 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002011 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002012 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2013 // true -> true.
2014 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002015 __ j(equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002016 // false -> false.
2017 __ CompareRoot(reg, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002018 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002019 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002020 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2021 // 'null' -> false.
2022 __ CompareRoot(reg, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002023 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002024 }
2025
2026 if (expected.Contains(ToBooleanStub::SMI)) {
2027 // Smis: 0 -> false, all other -> true.
2028 __ Cmp(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002029 __ j(equal, instr->FalseLabel(chunk_));
2030 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002031 } else if (expected.NeedsMap()) {
2032 // If we need a map later and have a Smi -> deopt.
2033 __ testb(reg, Immediate(kSmiTagMask));
2034 DeoptimizeIf(zero, instr->environment());
2035 }
2036
2037 const Register map = kScratchRegister;
2038 if (expected.NeedsMap()) {
2039 __ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002040
2041 if (expected.CanBeUndetectable()) {
2042 // Undetectable -> false.
2043 __ testb(FieldOperand(map, Map::kBitFieldOffset),
2044 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002045 __ j(not_zero, instr->FalseLabel(chunk_));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002046 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002047 }
2048
2049 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2050 // spec object -> true.
2051 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002052 __ j(above_equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002053 }
2054
2055 if (expected.Contains(ToBooleanStub::STRING)) {
2056 // String value -> false iff empty.
2057 Label not_string;
2058 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2059 __ j(above_equal, &not_string, Label::kNear);
2060 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002061 __ j(not_zero, instr->TrueLabel(chunk_));
2062 __ jmp(instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002063 __ bind(&not_string);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002064 }
2065
danno@chromium.orgc16e8282013-08-12 16:17:40 +00002066 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2067 // Symbol value -> true.
2068 __ CmpInstanceType(map, SYMBOL_TYPE);
2069 __ j(equal, instr->TrueLabel(chunk_));
2070 }
2071
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002072 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2073 // heap number -> false iff +0, -0, or NaN.
2074 Label not_heap_number;
2075 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
2076 __ j(not_equal, &not_heap_number, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002077 XMMRegister xmm_scratch = double_scratch0();
2078 __ xorps(xmm_scratch, xmm_scratch);
2079 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002080 __ j(zero, instr->FalseLabel(chunk_));
2081 __ jmp(instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002082 __ bind(&not_heap_number);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002083 }
2084
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002085 if (!expected.IsGeneric()) {
2086 // We've seen something for the first time -> deopt.
2087 // This can only happen if we are not generic already.
2088 DeoptimizeIf(no_condition, instr->environment());
2089 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002090 }
2091 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002092}
2093
2094
ager@chromium.org04921a82011-06-27 13:21:41 +00002095void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002096 if (!IsNextEmittedBlock(block)) {
2097 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002098 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002099}
2100
2101
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002102void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002103 EmitGoto(instr->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002104}
2105
2106
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002107inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002108 Condition cond = no_condition;
2109 switch (op) {
2110 case Token::EQ:
2111 case Token::EQ_STRICT:
2112 cond = equal;
2113 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002114 case Token::NE:
2115 case Token::NE_STRICT:
2116 cond = not_equal;
2117 break;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002118 case Token::LT:
2119 cond = is_unsigned ? below : less;
2120 break;
2121 case Token::GT:
2122 cond = is_unsigned ? above : greater;
2123 break;
2124 case Token::LTE:
2125 cond = is_unsigned ? below_equal : less_equal;
2126 break;
2127 case Token::GTE:
2128 cond = is_unsigned ? above_equal : greater_equal;
2129 break;
2130 case Token::IN:
2131 case Token::INSTANCEOF:
2132 default:
2133 UNREACHABLE();
2134 }
2135 return cond;
2136}
2137
2138
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002139void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002140 LOperand* left = instr->left();
2141 LOperand* right = instr->right();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002142 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002143
2144 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2145 // We can statically evaluate the comparison.
2146 double left_val = ToDouble(LConstantOperand::cast(left));
2147 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002148 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2149 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002150 EmitGoto(next_block);
2151 } else {
2152 if (instr->is_double()) {
2153 // Don't base result on EFLAGS when a NaN is involved. Instead
2154 // jump to the false block.
2155 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002156 __ j(parity_even, instr->FalseLabel(chunk_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002157 } else {
2158 int32_t value;
2159 if (right->IsConstantOperand()) {
2160 value = ToInteger32(LConstantOperand::cast(right));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002161 if (instr->hydrogen_value()->representation().IsSmi()) {
2162 __ Cmp(ToRegister(left), Smi::FromInt(value));
2163 } else {
2164 __ cmpl(ToRegister(left), Immediate(value));
2165 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002166 } else if (left->IsConstantOperand()) {
2167 value = ToInteger32(LConstantOperand::cast(left));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002168 if (instr->hydrogen_value()->representation().IsSmi()) {
2169 if (right->IsRegister()) {
2170 __ Cmp(ToRegister(right), Smi::FromInt(value));
2171 } else {
2172 __ Cmp(ToOperand(right), Smi::FromInt(value));
2173 }
2174 } else if (right->IsRegister()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002175 __ cmpl(ToRegister(right), Immediate(value));
2176 } else {
2177 __ cmpl(ToOperand(right), Immediate(value));
2178 }
2179 // We transposed the operands. Reverse the condition.
2180 cc = ReverseCondition(cc);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002181 } else if (instr->hydrogen_value()->representation().IsSmi()) {
2182 if (right->IsRegister()) {
2183 __ cmpq(ToRegister(left), ToRegister(right));
2184 } else {
2185 __ cmpq(ToRegister(left), ToOperand(right));
2186 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002187 } else {
2188 if (right->IsRegister()) {
2189 __ cmpl(ToRegister(left), ToRegister(right));
2190 } else {
2191 __ cmpl(ToRegister(left), ToOperand(right));
2192 }
2193 }
2194 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002195 EmitBranch(instr, cc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002196 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002197}
2198
2199
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002200void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002201 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002202
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002203 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002204 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002205 __ Cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002206 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002207 Register right = ToRegister(instr->right());
2208 __ cmpq(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002209 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002210 EmitBranch(instr, equal);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002211}
2212
2213
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002214void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2215 if (instr->hydrogen()->representation().IsTagged()) {
2216 Register input_reg = ToRegister(instr->object());
2217 __ Cmp(input_reg, factory()->the_hole_value());
2218 EmitBranch(instr, equal);
2219 return;
2220 }
2221
2222 XMMRegister input_reg = ToDoubleRegister(instr->object());
2223 __ ucomisd(input_reg, input_reg);
2224 EmitFalseBranch(instr, parity_odd);
2225
2226 __ subq(rsp, Immediate(kDoubleSize));
2227 __ movsd(MemOperand(rsp, 0), input_reg);
2228 __ addq(rsp, Immediate(kDoubleSize));
2229
2230 int offset = sizeof(kHoleNanUpper32);
2231 __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32));
2232 EmitBranch(instr, equal);
2233}
2234
2235
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002236void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2237 Representation rep = instr->hydrogen()->value()->representation();
2238 ASSERT(!rep.IsInteger32());
2239
2240 if (rep.IsDouble()) {
2241 XMMRegister value = ToDoubleRegister(instr->value());
2242 XMMRegister xmm_scratch = double_scratch0();
2243 __ xorps(xmm_scratch, xmm_scratch);
2244 __ ucomisd(xmm_scratch, value);
2245 EmitFalseBranch(instr, not_equal);
2246 __ movmskpd(kScratchRegister, value);
2247 __ testl(kScratchRegister, Immediate(1));
2248 EmitBranch(instr, not_zero);
2249 } else {
2250 Register value = ToRegister(instr->value());
2251 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
2252 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
2253 __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset),
2254 Immediate(0x80000000));
2255 EmitFalseBranch(instr, not_equal);
2256 __ cmpl(FieldOperand(value, HeapNumber::kMantissaOffset),
2257 Immediate(0x00000000));
2258 EmitBranch(instr, equal);
2259 }
2260}
2261
2262
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002263Condition LCodeGen::EmitIsObject(Register input,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002264 Label* is_not_object,
2265 Label* is_object) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002266 ASSERT(!input.is(kScratchRegister));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002267
2268 __ JumpIfSmi(input, is_not_object);
2269
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002270 __ CompareRoot(input, Heap::kNullValueRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002271 __ j(equal, is_object);
2272
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002273 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002274 // Undetectable objects behave like undefined.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002275 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002276 Immediate(1 << Map::kIsUndetectable));
2277 __ j(not_zero, is_not_object);
2278
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002279 __ movzxbl(kScratchRegister,
2280 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002281 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002282 __ j(below, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002283 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002284 return below_equal;
2285}
2286
2287
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002288void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002289 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002290
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002291 Condition true_cond = EmitIsObject(
2292 reg, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002293
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002294 EmitBranch(instr, true_cond);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002295}
2296
2297
erikcorry0ad885c2011-11-21 13:51:57 +00002298Condition LCodeGen::EmitIsString(Register input,
2299 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002300 Label* is_not_string,
2301 SmiCheck check_needed = INLINE_SMI_CHECK) {
2302 if (check_needed == INLINE_SMI_CHECK) {
2303 __ JumpIfSmi(input, is_not_string);
2304 }
2305
erikcorry0ad885c2011-11-21 13:51:57 +00002306 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2307
2308 return cond;
2309}
2310
2311
2312void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002313 Register reg = ToRegister(instr->value());
2314 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002315
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002316 SmiCheck check_needed =
2317 instr->hydrogen()->value()->IsHeapObject()
2318 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erikcorry0ad885c2011-11-21 13:51:57 +00002319
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002320 Condition true_cond = EmitIsString(
2321 reg, temp, instr->FalseLabel(chunk_), check_needed);
erikcorry0ad885c2011-11-21 13:51:57 +00002322
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002323 EmitBranch(instr, true_cond);
erikcorry0ad885c2011-11-21 13:51:57 +00002324}
2325
2326
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002327void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002328 Condition is_smi;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002329 if (instr->value()->IsRegister()) {
2330 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002331 is_smi = masm()->CheckSmi(input);
2332 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002333 Operand input = ToOperand(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002334 is_smi = masm()->CheckSmi(input);
2335 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002336 EmitBranch(instr, is_smi);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002337}
2338
2339
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002340void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002341 Register input = ToRegister(instr->value());
2342 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002343
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002344 if (!instr->hydrogen()->value()->IsHeapObject()) {
2345 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2346 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002347 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
2348 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
2349 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002350 EmitBranch(instr, not_zero);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002351}
2352
2353
erikcorry0ad885c2011-11-21 13:51:57 +00002354void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002355 ASSERT(ToRegister(instr->context()).is(rsi));
erikcorry0ad885c2011-11-21 13:51:57 +00002356 Token::Value op = instr->op();
erikcorry0ad885c2011-11-21 13:51:57 +00002357
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002358 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002359 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2360
2361 Condition condition = TokenToCondition(op, false);
2362 __ testq(rax, rax);
2363
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002364 EmitBranch(instr, condition);
erikcorry0ad885c2011-11-21 13:51:57 +00002365}
2366
2367
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002368static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002369 InstanceType from = instr->from();
2370 InstanceType to = instr->to();
2371 if (from == FIRST_TYPE) return to;
2372 ASSERT(from == to || to == LAST_TYPE);
2373 return from;
2374}
2375
2376
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002377static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002378 InstanceType from = instr->from();
2379 InstanceType to = instr->to();
2380 if (from == to) return equal;
2381 if (to == LAST_TYPE) return above_equal;
2382 if (from == FIRST_TYPE) return below_equal;
2383 UNREACHABLE();
2384 return equal;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002385}
2386
2387
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002388void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002389 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002390
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002391 if (!instr->hydrogen()->value()->IsHeapObject()) {
2392 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2393 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002394
2395 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002396 EmitBranch(instr, BranchCondition(instr->hydrogen()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002397}
2398
2399
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002400void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002401 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002402 Register result = ToRegister(instr->result());
2403
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002404 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002405
2406 __ movl(result, FieldOperand(input, String::kHashFieldOffset));
2407 ASSERT(String::kHashShift >= kSmiTagSize);
2408 __ IndexFromHash(result, result);
2409}
2410
2411
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002412void LCodeGen::DoHasCachedArrayIndexAndBranch(
2413 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002414 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002415
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002416 __ testl(FieldOperand(input, String::kHashFieldOffset),
2417 Immediate(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002418 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002419}
2420
2421
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002422// Branches to a label or falls through with the answer in the z flag.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002423// Trashes the temp register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002424void LCodeGen::EmitClassOfTest(Label* is_true,
2425 Label* is_false,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002426 Handle<String> class_name,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002427 Register input,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002428 Register temp,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002429 Register temp2) {
2430 ASSERT(!input.is(temp));
2431 ASSERT(!input.is(temp2));
2432 ASSERT(!temp.is(temp2));
2433
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002434 __ JumpIfSmi(input, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002435
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002436 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002437 // Assuming the following assertions, we can use the same compares to test
2438 // for both being a function type and being in the object type range.
2439 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2440 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2441 FIRST_SPEC_OBJECT_TYPE + 1);
2442 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2443 LAST_SPEC_OBJECT_TYPE - 1);
2444 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2445 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2446 __ j(below, is_false);
2447 __ j(equal, is_true);
2448 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2449 __ j(equal, is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002450 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002451 // Faster code path to avoid two compares: subtract lower bound from the
2452 // actual type and do a signed compare with the width of the type range.
2453 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002454 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
2455 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2456 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2457 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002458 __ j(above, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002459 }
2460
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002461 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002462 // Check if the constructor in the map is a function.
2463 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset));
2464
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002465 // Objects with a non-function constructor have class 'Object'.
2466 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002467 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002468 __ j(not_equal, is_true);
2469 } else {
2470 __ j(not_equal, is_false);
2471 }
2472
2473 // temp now contains the constructor function. Grab the
2474 // instance class name from there.
2475 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2476 __ movq(temp, FieldOperand(temp,
2477 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002478 // The class name we are testing against is internalized since it's a literal.
2479 // The name in the constructor is internalized because of the way the context
2480 // is booted. This routine isn't expected to work for random API-created
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002481 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002482 // syntax. Since both sides are internalized it is sufficient to use an
2483 // identity comparison.
2484 ASSERT(class_name->IsInternalizedString());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002485 __ Cmp(temp, class_name);
2486 // End with the answer in the z flag.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002487}
2488
2489
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002490void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002491 Register input = ToRegister(instr->value());
2492 Register temp = ToRegister(instr->temp());
2493 Register temp2 = ToRegister(instr->temp2());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002494 Handle<String> class_name = instr->hydrogen()->class_name();
2495
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002496 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2497 class_name, input, temp, temp2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002498
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002499 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002500}
2501
2502
2503void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002504 Register reg = ToRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002505
2506 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002507 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002508}
2509
2510
2511void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002512 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002513 InstanceofStub stub(InstanceofStub::kNoFlags);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002514 __ push(ToRegister(instr->left()));
2515 __ push(ToRegister(instr->right()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002516 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002517 Label true_value, done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002518 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002519 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002520 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002521 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002522 __ bind(&true_value);
2523 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2524 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002525}
2526
2527
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002528void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002529 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002530 public:
2531 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2532 LInstanceOfKnownGlobal* instr)
2533 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002534 virtual void Generate() V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002535 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002536 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002537 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002538 Label* map_check() { return &map_check_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002539 private:
2540 LInstanceOfKnownGlobal* instr_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002541 Label map_check_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002542 };
2543
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002544 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002545 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002546 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002547
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002548 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002549 Register object = ToRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002550
2551 // A Smi is not an instance of anything.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002552 __ JumpIfSmi(object, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002553
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002554 // This is the inlined call site instanceof cache. The two occurences of the
2555 // hole value will be patched to the last map/result pair generated by the
2556 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002557 Label cache_miss;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002558 // Use a temp register to avoid memory operands with variable lengths.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002559 Register map = ToRegister(instr->temp());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002560 __ movq(map, FieldOperand(object, HeapObject::kMapOffset));
2561 __ bind(deferred->map_check()); // Label for calculating code patching.
danno@chromium.org41728482013-06-12 22:31:22 +00002562 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2563 __ movq(kScratchRegister, cache_cell, RelocInfo::CELL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002564 __ cmpq(map, Operand(kScratchRegister, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002565 __ j(not_equal, &cache_miss, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002566 // Patched to load either true or false.
2567 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
2568#ifdef DEBUG
2569 // Check that the code size between patch label and patch sites is invariant.
2570 Label end_of_patched_code;
2571 __ bind(&end_of_patched_code);
2572 ASSERT(true);
2573#endif
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002574 __ jmp(&done, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002575
2576 // The inlined call site cache did not match. Check for null and string
2577 // before calling the deferred code.
2578 __ bind(&cache_miss); // Null is not an instance of anything.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002579 __ CompareRoot(object, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002580 __ j(equal, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002581
2582 // String values are not instances of anything.
2583 __ JumpIfNotString(object, kScratchRegister, deferred->entry());
2584
2585 __ bind(&false_result);
2586 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2587
2588 __ bind(deferred->exit());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002589 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002590}
2591
2592
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002593void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2594 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002595 {
2596 PushSafepointRegistersScope scope(this);
2597 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
2598 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck);
2599 InstanceofStub stub(flags);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002600
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002601 __ push(ToRegister(instr->value()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002602 __ Push(instr->function());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002603
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002604 static const int kAdditionalDelta = 10;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002605 int delta =
2606 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002607 ASSERT(delta >= 0);
2608 __ push_imm32(delta);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002609
2610 // We are pushing three values on the stack but recording a
2611 // safepoint with two arguments because stub is going to
2612 // remove the third argument from the stack before jumping
2613 // to instanceof builtin on the slow path.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002614 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002615 RelocInfo::CODE_TARGET,
2616 instr,
2617 RECORD_SAFEPOINT_WITH_REGISTERS,
2618 2);
2619 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002620 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002621 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002622 // Move result to a register that survives the end of the
2623 // PushSafepointRegisterScope.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002624 __ movq(kScratchRegister, rax);
2625 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002626 __ testq(kScratchRegister, kScratchRegister);
2627 Label load_false;
2628 Label done;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002629 __ j(not_zero, &load_false, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002630 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002631 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002632 __ bind(&load_false);
2633 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2634 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002635}
2636
2637
2638void LCodeGen::DoCmpT(LCmpT* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002639 ASSERT(ToRegister(instr->context()).is(rsi));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002640 Token::Value op = instr->op();
2641
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002642 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002643 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2644
2645 Condition condition = TokenToCondition(op, false);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002646 Label true_value, done;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002647 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002648 __ j(condition, &true_value, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002649 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002650 __ jmp(&done, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002651 __ bind(&true_value);
2652 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2653 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002654}
2655
2656
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002657void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002658 if (FLAG_trace && info()->IsOptimizing()) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002659 // Preserve the return value on the stack and rely on the runtime call
2660 // to return the value in the same register. We're leaving the code
2661 // managed by the register allocator and tearing down the frame, it's
2662 // safe to write to the context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002663 __ push(rax);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002664 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002665 __ CallRuntime(Runtime::kTraceExit, 1);
2666 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002667 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002668 RestoreCallerDoubles();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002669 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002670 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002671 if (NeedsEagerFrame()) {
2672 __ movq(rsp, rbp);
2673 __ pop(rbp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002674 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002675 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002676 if (instr->has_constant_parameter_count()) {
2677 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
2678 rcx);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002679 } else {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002680 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002681 // The argument count parameter is a smi
2682 __ SmiToInteger32(reg, reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002683 Register return_addr_reg = reg.is(rcx) ? rbx : rcx;
danno@chromium.org59400602013-08-13 17:09:37 +00002684 __ PopReturnAddressTo(return_addr_reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002685 __ shl(reg, Immediate(kPointerSizeLog2));
2686 __ addq(rsp, reg);
2687 __ jmp(return_addr_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002688 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002689 if (no_frame_start != -1) {
2690 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2691 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002692}
2693
2694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002695void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002696 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002697 __ LoadGlobalCell(result, instr->hydrogen()->cell().handle());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002698 if (instr->hydrogen()->RequiresHoleCheck()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002699 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2700 DeoptimizeIf(equal, instr->environment());
2701 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002702}
2703
2704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002705void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002706 ASSERT(ToRegister(instr->context()).is(rsi));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002707 ASSERT(ToRegister(instr->global_object()).is(rax));
2708 ASSERT(ToRegister(instr->result()).is(rax));
2709
2710 __ Move(rcx, instr->name());
2711 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2712 RelocInfo::CODE_TARGET_CONTEXT;
2713 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2714 CallCode(ic, mode, instr);
2715}
2716
2717
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002718void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002719 Register value = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002720 Handle<Cell> cell_handle = instr->hydrogen()->cell().handle();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002721
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002722 // If the cell we are storing to contains the hole it could have
2723 // been deleted from the property dictionary. In that case, we need
2724 // to update the property details in the property dictionary to mark
2725 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002726 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002727 // We have a temp because CompareRoot might clobber kScratchRegister.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002728 Register cell = ToRegister(instr->temp());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002729 ASSERT(!value.is(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00002730 __ movq(cell, cell_handle, RelocInfo::CELL);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002731 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002732 DeoptimizeIf(equal, instr->environment());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002733 // Store the value.
2734 __ movq(Operand(cell, 0), value);
2735 } else {
2736 // Store the value.
danno@chromium.org41728482013-06-12 22:31:22 +00002737 __ movq(kScratchRegister, cell_handle, RelocInfo::CELL);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002738 __ movq(Operand(kScratchRegister, 0), value);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002739 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002740 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002741}
2742
2743
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002744void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002745 ASSERT(ToRegister(instr->context()).is(rsi));
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002746 ASSERT(ToRegister(instr->global_object()).is(rdx));
2747 ASSERT(ToRegister(instr->value()).is(rax));
2748
2749 __ Move(rcx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002750 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002751 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2752 : isolate()->builtins()->StoreIC_Initialize();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002753 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2754}
2755
2756
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002757void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002758 Register context = ToRegister(instr->context());
2759 Register result = ToRegister(instr->result());
2760 __ movq(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002761 if (instr->hydrogen()->RequiresHoleCheck()) {
2762 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002763 if (instr->hydrogen()->DeoptimizesOnHole()) {
2764 DeoptimizeIf(equal, instr->environment());
2765 } else {
2766 Label is_not_hole;
2767 __ j(not_equal, &is_not_hole, Label::kNear);
2768 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2769 __ bind(&is_not_hole);
2770 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002771 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002772}
2773
2774
2775void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2776 Register context = ToRegister(instr->context());
2777 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002778
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002779 Operand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002780
2781 Label skip_assignment;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002782 if (instr->hydrogen()->RequiresHoleCheck()) {
2783 __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002784 if (instr->hydrogen()->DeoptimizesOnHole()) {
2785 DeoptimizeIf(equal, instr->environment());
2786 } else {
2787 __ j(not_equal, &skip_assignment);
2788 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002789 }
2790 __ movq(target, value);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002791
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002792 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002793 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002794 instr->hydrogen()->value()->IsHeapObject()
2795 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002796 int offset = Context::SlotOffset(instr->slot_index());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002797 Register scratch = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002798 __ RecordWriteContextSlot(context,
2799 offset,
2800 value,
2801 scratch,
2802 kSaveFPRegs,
2803 EMIT_REMEMBERED_SET,
2804 check_needed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002805 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002806
2807 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002808}
2809
2810
2811void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002812 HObjectAccess access = instr->hydrogen()->access();
2813 int offset = access.offset();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002814
2815 if (access.IsExternalMemory()) {
2816 Register result = ToRegister(instr->result());
2817 if (instr->object()->IsConstantOperand()) {
2818 ASSERT(result.is(rax));
2819 __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
2820 } else {
2821 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002822 __ Load(result, MemOperand(object, offset), access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002823 }
2824 return;
2825 }
2826
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002827 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002828 if (FLAG_track_double_fields &&
2829 instr->hydrogen()->representation().IsDouble()) {
2830 XMMRegister result = ToDoubleRegister(instr->result());
2831 __ movsd(result, FieldOperand(object, offset));
2832 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002833 }
2834
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002835 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002836 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002837 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002838 object = result;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002839 }
jkummerow@chromium.org113035e2013-12-13 15:13:40 +00002840
2841 Representation representation = access.representation();
2842 if (representation.IsSmi() &&
2843 instr->hydrogen()->representation().IsInteger32()) {
2844 // Read int value directly from upper half of the smi.
2845 STATIC_ASSERT(kSmiTag == 0);
2846 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
2847 offset += kPointerSize / 2;
2848 representation = Representation::Integer32();
2849 }
2850 __ Load(result, FieldOperand(object, offset), representation);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002851}
2852
2853
2854void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002855 ASSERT(ToRegister(instr->context()).is(rsi));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002856 ASSERT(ToRegister(instr->object()).is(rax));
2857 ASSERT(ToRegister(instr->result()).is(rax));
2858
2859 __ Move(rcx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002860 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002861 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002862}
2863
2864
2865void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002866 Register function = ToRegister(instr->function());
2867 Register result = ToRegister(instr->result());
2868
2869 // Check that the function really is a function.
2870 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2871 DeoptimizeIf(not_equal, instr->environment());
2872
2873 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002874 Label non_instance;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002875 __ testb(FieldOperand(result, Map::kBitFieldOffset),
2876 Immediate(1 << Map::kHasNonInstancePrototype));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002877 __ j(not_zero, &non_instance, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002878
2879 // Get the prototype or initial map from the function.
2880 __ movq(result,
2881 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2882
2883 // Check that the function has a prototype or an initial map.
2884 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2885 DeoptimizeIf(equal, instr->environment());
2886
2887 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002888 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002889 __ CmpObjectType(result, MAP_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002890 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002891
2892 // Get the prototype from the initial map.
2893 __ movq(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002894 __ jmp(&done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002895
2896 // Non-instance prototype: Fetch prototype from constructor field
2897 // in the function's map.
2898 __ bind(&non_instance);
2899 __ movq(result, FieldOperand(result, Map::kConstructorOffset));
2900
2901 // All done.
2902 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002903}
2904
2905
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002906void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
2907 Register result = ToRegister(instr->result());
2908 __ LoadRoot(result, instr->index());
2909}
2910
2911
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002912void LCodeGen::DoLoadExternalArrayPointer(
2913 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002914 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002915 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002916 __ movq(result, FieldOperand(input,
2917 ExternalPixelArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002918}
2919
2920
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002921void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002922 Register arguments = ToRegister(instr->arguments());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002923 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002924
2925 if (instr->length()->IsConstantOperand() &&
2926 instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002927 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2928 int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length()));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002929 StackArgumentsAccessor args(arguments, const_length,
2930 ARGUMENTS_DONT_CONTAIN_RECEIVER);
2931 __ movq(result, args.GetArgumentOperand(const_index));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002932 } else {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002933 Register length = ToRegister(instr->length());
2934 // There are two words between the frame pointer and the last argument.
2935 // Subtracting from length accounts for one of them add one more.
2936 if (instr->index()->IsRegister()) {
2937 __ subl(length, ToRegister(instr->index()));
2938 } else {
2939 __ subl(length, ToOperand(instr->index()));
2940 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002941 StackArgumentsAccessor args(arguments, length,
2942 ARGUMENTS_DONT_CONTAIN_RECEIVER);
2943 __ movq(result, args.GetArgumentOperand(0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002944 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002945}
2946
2947
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002948void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
2949 ElementsKind elements_kind = instr->elements_kind();
2950 LOperand* key = instr->key();
2951 if (!key->IsConstantOperand()) {
2952 Register key_reg = ToRegister(key);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002953 // Even though the HLoad/StoreKeyed (in this case) instructions force
2954 // the input representation for the key to be an integer, the input
2955 // gets replaced during bound check elimination with the index argument
2956 // to the bounds check, which can be tagged, so that case must be
2957 // handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002958 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002959 // Sign extend key because it could be a 32 bit negative value
2960 // and the dehoisted address computation happens in 64 bits
2961 __ movsxlq(key_reg, key_reg);
2962 }
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002963 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002964 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002965 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002966 key,
2967 elements_kind,
2968 0,
2969 instr->additional_index()));
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002970
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002971 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002972 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002973 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002974 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002975 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002976 __ movsd(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002977 } else {
2978 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002979 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002980 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002981 __ movsxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002982 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002983 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2984 case EXTERNAL_PIXEL_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002985 __ movzxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002986 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002987 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002988 __ movsxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002989 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002990 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002991 __ movzxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002992 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002993 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002994 __ movsxlq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002995 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002996 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002997 __ movl(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002998 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2999 __ testl(result, result);
3000 DeoptimizeIf(negative, instr->environment());
3001 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003002 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003003 case EXTERNAL_FLOAT_ELEMENTS:
3004 case EXTERNAL_DOUBLE_ELEMENTS:
3005 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003006 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003007 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003008 case FAST_HOLEY_ELEMENTS:
3009 case FAST_HOLEY_SMI_ELEMENTS:
3010 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003011 case DICTIONARY_ELEMENTS:
3012 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003013 UNREACHABLE();
3014 break;
3015 }
3016 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003017}
3018
3019
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003020void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3021 XMMRegister result(ToDoubleRegister(instr->result()));
3022 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003023 if (!key->IsConstantOperand()) {
3024 Register key_reg = ToRegister(key);
3025 // Even though the HLoad/StoreKeyed instructions force the input
3026 // representation for the key to be an integer, the input gets replaced
3027 // during bound check elimination with the index argument to the bounds
3028 // check, which can be tagged, so that case must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003029 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003030 // Sign extend key because it could be a 32 bit negative value
3031 // and the dehoisted address computation happens in 64 bits
3032 __ movsxlq(key_reg, key_reg);
3033 }
3034 }
3035
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003036 if (instr->hydrogen()->RequiresHoleCheck()) {
3037 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3038 sizeof(kHoleNanLower32);
3039 Operand hole_check_operand = BuildFastArrayOperand(
3040 instr->elements(),
3041 key,
3042 FAST_DOUBLE_ELEMENTS,
3043 offset,
3044 instr->additional_index());
3045 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
3046 DeoptimizeIf(equal, instr->environment());
3047 }
3048
3049 Operand double_load_operand = BuildFastArrayOperand(
3050 instr->elements(),
3051 key,
3052 FAST_DOUBLE_ELEMENTS,
3053 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3054 instr->additional_index());
3055 __ movsd(result, double_load_operand);
3056}
3057
3058
3059void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003060 HLoadKeyed* hinstr = instr->hydrogen();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003061 Register result = ToRegister(instr->result());
3062 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003063 if (!key->IsConstantOperand()) {
3064 Register key_reg = ToRegister(key);
3065 // Even though the HLoad/StoreKeyedFastElement instructions force
3066 // the input representation for the key to be an integer, the input
3067 // gets replaced during bound check elimination with the index
3068 // argument to the bounds check, which can be tagged, so that
3069 // case must be handled here, too.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003070 if (hinstr->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003071 // Sign extend key because it could be a 32 bit negative value
3072 // and the dehoisted address computation happens in 64 bits
3073 __ movsxlq(key_reg, key_reg);
3074 }
3075 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003076
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003077 bool requires_hole_check = hinstr->RequiresHoleCheck();
3078 int offset = FixedArray::kHeaderSize - kHeapObjectTag;
3079 Representation representation = hinstr->representation();
3080
3081 if (representation.IsInteger32() &&
3082 hinstr->elements_kind() == FAST_SMI_ELEMENTS) {
3083 ASSERT(!requires_hole_check);
3084 // Read int value directly from upper half of the smi.
3085 STATIC_ASSERT(kSmiTag == 0);
3086 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
3087 offset += kPointerSize / 2;
3088 }
3089
3090 __ Load(result,
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003091 BuildFastArrayOperand(instr->elements(),
3092 key,
3093 FAST_ELEMENTS,
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003094 offset,
3095 instr->additional_index()),
3096 representation);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003097
3098 // Check for the hole value.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003099 if (requires_hole_check) {
3100 if (IsFastSmiElementsKind(hinstr->elements_kind())) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003101 Condition smi = __ CheckSmi(result);
3102 DeoptimizeIf(NegateCondition(smi), instr->environment());
3103 } else {
3104 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
3105 DeoptimizeIf(equal, instr->environment());
3106 }
3107 }
3108}
3109
3110
3111void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3112 if (instr->is_external()) {
3113 DoLoadKeyedExternalArray(instr);
3114 } else if (instr->hydrogen()->representation().IsDouble()) {
3115 DoLoadKeyedFixedDoubleArray(instr);
3116 } else {
3117 DoLoadKeyedFixedArray(instr);
3118 }
3119}
3120
3121
3122Operand LCodeGen::BuildFastArrayOperand(
3123 LOperand* elements_pointer,
3124 LOperand* key,
3125 ElementsKind elements_kind,
3126 uint32_t offset,
3127 uint32_t additional_index) {
3128 Register elements_pointer_reg = ToRegister(elements_pointer);
3129 int shift_size = ElementsKindToShiftSize(elements_kind);
3130 if (key->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003131 int32_t constant_value = ToInteger32(LConstantOperand::cast(key));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003132 if (constant_value & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003133 Abort(kArrayIndexConstantValueTooBig);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003134 }
3135 return Operand(elements_pointer_reg,
3136 ((constant_value + additional_index) << shift_size)
3137 + offset);
3138 } else {
3139 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3140 return Operand(elements_pointer_reg,
3141 ToRegister(key),
3142 scale_factor,
3143 offset + (additional_index << shift_size));
3144 }
3145}
3146
3147
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003148void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003149 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003150 ASSERT(ToRegister(instr->object()).is(rdx));
3151 ASSERT(ToRegister(instr->key()).is(rax));
3152
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003153 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003154 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003155}
3156
3157
3158void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003159 Register result = ToRegister(instr->result());
3160
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003161 if (instr->hydrogen()->from_inlined()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003162 __ lea(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003163 } else {
3164 // Check for arguments adapter frame.
3165 Label done, adapted;
3166 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3167 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
3168 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3169 __ j(equal, &adapted, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003170
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003171 // No arguments adaptor frame.
3172 __ movq(result, rbp);
3173 __ jmp(&done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003174
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003175 // Arguments adaptor frame present.
3176 __ bind(&adapted);
3177 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003178
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003179 // Result is the frame pointer for the frame if not adapted and for the real
3180 // frame below the adaptor frame if adapted.
3181 __ bind(&done);
3182 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003183}
3184
3185
3186void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003187 Register result = ToRegister(instr->result());
3188
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003189 Label done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003190
3191 // If no arguments adaptor frame the number of arguments is fixed.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003192 if (instr->elements()->IsRegister()) {
3193 __ cmpq(rbp, ToRegister(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003194 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003195 __ cmpq(rbp, ToOperand(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003196 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003197 __ movl(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003198 __ j(equal, &done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003199
3200 // Arguments adaptor frame present. Get argument length from there.
3201 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003202 __ SmiToInteger32(result,
3203 Operand(result,
3204 ArgumentsAdaptorFrameConstants::kLengthOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003205
3206 // Argument length is in result register.
3207 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003208}
3209
3210
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003211void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003212 Register receiver = ToRegister(instr->receiver());
3213 Register function = ToRegister(instr->function());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003214
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003215 // If the receiver is null or undefined, we have to pass the global
3216 // object as a receiver to normal functions. Values have to be
3217 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003218 Label global_object, receiver_ok;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003219 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003220
3221 // Do not transform the receiver to object for strict mode
3222 // functions.
3223 __ movq(kScratchRegister,
3224 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3225 __ testb(FieldOperand(kScratchRegister,
3226 SharedFunctionInfo::kStrictModeByteOffset),
3227 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003228 __ j(not_equal, &receiver_ok, dist);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003229
3230 // Do not transform the receiver to object for builtins.
3231 __ testb(FieldOperand(kScratchRegister,
3232 SharedFunctionInfo::kNativeByteOffset),
3233 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003234 __ j(not_equal, &receiver_ok, dist);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003235
3236 // Normal function. Replace undefined or null with global receiver.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003237 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003238 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003239 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003240 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003241
3242 // The receiver should be a JS object.
3243 Condition is_smi = __ CheckSmi(receiver);
3244 DeoptimizeIf(is_smi, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003245 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003246 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003247 __ jmp(&receiver_ok, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003248
3249 __ bind(&global_object);
3250 // TODO(kmillikin): We have a hydrogen value for the global object. See
3251 // if it's better to use it than to explicitly fetch it from the context
3252 // here.
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00003253 CallStubCompiler::FetchGlobalProxy(masm(), receiver, function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003254 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003255}
3256
3257
3258void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3259 Register receiver = ToRegister(instr->receiver());
3260 Register function = ToRegister(instr->function());
3261 Register length = ToRegister(instr->length());
3262 Register elements = ToRegister(instr->elements());
3263 ASSERT(receiver.is(rax)); // Used for parameter count.
3264 ASSERT(function.is(rdi)); // Required by InvokeFunction.
3265 ASSERT(ToRegister(instr->result()).is(rax));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003266
3267 // Copy the arguments to this function possibly from the
3268 // adaptor frame below it.
3269 const uint32_t kArgumentsLimit = 1 * KB;
3270 __ cmpq(length, Immediate(kArgumentsLimit));
3271 DeoptimizeIf(above, instr->environment());
3272
3273 __ push(receiver);
3274 __ movq(receiver, length);
3275
3276 // Loop through the arguments pushing them onto the execution
3277 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003278 Label invoke, loop;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003279 // length is a small non-negative integer, due to the test above.
3280 __ testl(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003281 __ j(zero, &invoke, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003282 __ bind(&loop);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003283 StackArgumentsAccessor args(elements, length,
3284 ARGUMENTS_DONT_CONTAIN_RECEIVER);
3285 __ push(args.GetArgumentOperand(0));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003286 __ decl(length);
3287 __ j(not_zero, &loop);
3288
3289 // Invoke the function.
3290 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003291 ASSERT(instr->HasPointerMap());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003292 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003293 SafepointGenerator safepoint_generator(
3294 this, pointers, Safepoint::kLazyDeopt);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003295 ParameterCount actual(rax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003296 __ InvokeFunction(function, actual, CALL_FUNCTION,
3297 safepoint_generator, CALL_AS_METHOD);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003298}
3299
3300
3301void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003302 LOperand* argument = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00003303 EmitPushTaggedOperand(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003304}
3305
3306
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003307void LCodeGen::DoDrop(LDrop* instr) {
3308 __ Drop(instr->count());
3309}
3310
3311
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003312void LCodeGen::DoThisFunction(LThisFunction* instr) {
3313 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003314 __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003315}
3316
3317
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003318void LCodeGen::DoContext(LContext* instr) {
3319 Register result = ToRegister(instr->result());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003320 if (info()->IsOptimizing()) {
3321 __ movq(result, Operand(rbp, StandardFrameConstants::kContextOffset));
3322 } else {
3323 // If there is no frame, the context must be in rsi.
3324 ASSERT(result.is(rsi));
3325 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003326}
3327
3328
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003329void LCodeGen::DoOuterContext(LOuterContext* instr) {
3330 Register context = ToRegister(instr->context());
3331 Register result = ToRegister(instr->result());
3332 __ movq(result,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003333 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003334}
3335
3336
yangguo@chromium.org56454712012-02-16 15:33:53 +00003337void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003338 ASSERT(ToRegister(instr->context()).is(rsi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003339 __ push(rsi); // The context is the first argument.
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003340 __ Push(instr->hydrogen()->pairs());
yangguo@chromium.org56454712012-02-16 15:33:53 +00003341 __ Push(Smi::FromInt(instr->hydrogen()->flags()));
3342 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3343}
3344
3345
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003346void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003347 Register context = ToRegister(instr->context());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003348 Register result = ToRegister(instr->result());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003349 __ movq(result,
3350 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003351}
3352
3353
3354void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003355 Register global = ToRegister(instr->global());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003356 Register result = ToRegister(instr->result());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003357 __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003358}
3359
3360
3361void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003362 int formal_parameter_count,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003363 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003364 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003365 CallKind call_kind,
3366 RDIState rdi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003367 bool dont_adapt_arguments =
3368 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3369 bool can_invoke_directly =
3370 dont_adapt_arguments || formal_parameter_count == arity;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003371
3372 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003373
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003374 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003375 if (rdi_state == RDI_UNINITIALIZED) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003376 __ Move(rdi, function);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003377 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003378
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003379 // Change context.
3380 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003381
3382 // Set rax to arguments count if adaption is not needed. Assumes that rax
3383 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003384 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003385 __ Set(rax, arity);
3386 }
3387
3388 // Invoke function.
3389 __ SetCallKind(rcx, call_kind);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003390 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003391 __ CallSelf();
3392 } else {
3393 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
3394 }
3395
3396 // Set up deoptimization.
3397 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
3398 } else {
3399 // We need to adapt arguments.
3400 SafepointGenerator generator(
3401 this, pointers, Safepoint::kLazyDeopt);
3402 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003403 ParameterCount expected(formal_parameter_count);
3404 __ InvokeFunction(
3405 function, expected, count, CALL_FUNCTION, generator, call_kind);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003406 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003407}
3408
3409
3410void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003411 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003412 CallKnownFunction(instr->hydrogen()->function(),
3413 instr->hydrogen()->formal_parameter_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00003414 instr->arity(),
3415 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003416 CALL_AS_METHOD,
3417 RDI_UNINITIALIZED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003418}
3419
3420
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003421void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003422 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003423 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3424 Heap::kHeapNumberMapRootIndex);
3425 DeoptimizeIf(not_equal, instr->environment());
3426
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003427 Label slow, allocated, done;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003428 Register tmp = input_reg.is(rax) ? rcx : rax;
3429 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx;
3430
3431 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003432 PushSafepointRegistersScope scope(this);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003433
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003434 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3435 // Check the sign of the argument. If the argument is positive, just
3436 // return it. We do not need to patch the stack since |input| and
3437 // |result| are the same register and |input| will be restored
3438 // unchanged by popping safepoint registers.
3439 __ testl(tmp, Immediate(HeapNumber::kSignMask));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003440 __ j(zero, &done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003441
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003442 __ AllocateHeapNumber(tmp, tmp2, &slow);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003443 __ jmp(&allocated, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003444
3445 // Slow case: Call the runtime system to do the number allocation.
3446 __ bind(&slow);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003447 CallRuntimeFromDeferred(
3448 Runtime::kAllocateHeapNumber, 0, instr, instr->context());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003449 // Set the pointer to the new heap number in tmp.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003450 if (!tmp.is(rax)) __ movq(tmp, rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003451 // Restore input_reg after call to runtime.
3452 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3453
3454 __ bind(&allocated);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00003455 __ MoveDouble(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003456 __ shl(tmp2, Immediate(1));
3457 __ shr(tmp2, Immediate(1));
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00003458 __ MoveDouble(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003459 __ StoreToSafepointRegisterSlot(input_reg, tmp);
3460
3461 __ bind(&done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003462}
3463
3464
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003465void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003466 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003467 __ testl(input_reg, input_reg);
3468 Label is_positive;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003469 __ j(not_sign, &is_positive, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003470 __ negl(input_reg); // Sets flags.
3471 DeoptimizeIf(negative, instr->environment());
3472 __ bind(&is_positive);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003473}
3474
3475
danno@chromium.org59400602013-08-13 17:09:37 +00003476void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) {
3477 Register input_reg = ToRegister(instr->value());
3478 __ testq(input_reg, input_reg);
3479 Label is_positive;
3480 __ j(not_sign, &is_positive, Label::kNear);
3481 __ neg(input_reg); // Sets flags.
3482 DeoptimizeIf(negative, instr->environment());
3483 __ bind(&is_positive);
3484}
3485
3486
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003487void LCodeGen::DoMathAbs(LMathAbs* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003488 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003489 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003490 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003491 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003492 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003493 virtual void Generate() V8_OVERRIDE {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003494 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3495 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003496 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003497 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003498 LMathAbs* instr_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003499 };
3500
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003501 ASSERT(instr->value()->Equals(instr->result()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003502 Representation r = instr->hydrogen()->value()->representation();
3503
3504 if (r.IsDouble()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003505 XMMRegister scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003506 XMMRegister input_reg = ToDoubleRegister(instr->value());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003507 __ xorps(scratch, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003508 __ subsd(scratch, input_reg);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00003509 __ andps(input_reg, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003510 } else if (r.IsInteger32()) {
3511 EmitIntegerMathAbs(instr);
danno@chromium.org59400602013-08-13 17:09:37 +00003512 } else if (r.IsSmi()) {
3513 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003514 } else { // Tagged case.
3515 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003516 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003517 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003518 // Smi check.
3519 __ JumpIfNotSmi(input_reg, deferred->entry());
danno@chromium.org59400602013-08-13 17:09:37 +00003520 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003521 __ bind(deferred->exit());
3522 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003523}
3524
3525
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003526void LCodeGen::DoMathFloor(LMathFloor* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003527 XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003528 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003529 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003530
danno@chromium.org160a7b02011-04-18 15:51:38 +00003531 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003532 CpuFeatureScope scope(masm(), SSE4_1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003533 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3534 // Deoptimize if minus zero.
3535 __ movq(output_reg, input_reg);
3536 __ subq(output_reg, Immediate(1));
3537 DeoptimizeIf(overflow, instr->environment());
3538 }
3539 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3540 __ cvttsd2si(output_reg, xmm_scratch);
3541 __ cmpl(output_reg, Immediate(0x80000000));
3542 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003543 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003544 Label negative_sign, done;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003545 // Deoptimize on unordered.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003546 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3547 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003548 DeoptimizeIf(parity_even, instr->environment());
3549 __ j(below, &negative_sign, Label::kNear);
3550
danno@chromium.org160a7b02011-04-18 15:51:38 +00003551 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003552 // Check for negative zero.
3553 Label positive_sign;
3554 __ j(above, &positive_sign, Label::kNear);
3555 __ movmskpd(output_reg, input_reg);
3556 __ testq(output_reg, Immediate(1));
3557 DeoptimizeIf(not_zero, instr->environment());
3558 __ Set(output_reg, 0);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003559 __ jmp(&done, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003560 __ bind(&positive_sign);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003561 }
3562
3563 // Use truncating instruction (OK because input is positive).
3564 __ cvttsd2si(output_reg, input_reg);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003565 // Overflow is signalled with minint.
3566 __ cmpl(output_reg, Immediate(0x80000000));
3567 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003568 __ jmp(&done, Label::kNear);
3569
3570 // Non-zero negative reaches here.
3571 __ bind(&negative_sign);
3572 // Truncate, then compare and compensate.
3573 __ cvttsd2si(output_reg, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003574 __ Cvtlsi2sd(xmm_scratch, output_reg);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003575 __ ucomisd(input_reg, xmm_scratch);
3576 __ j(equal, &done, Label::kNear);
3577 __ subl(output_reg, Immediate(1));
3578 DeoptimizeIf(overflow, instr->environment());
3579
3580 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003581 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003582}
3583
3584
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003585void LCodeGen::DoMathRound(LMathRound* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003586 const XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003587 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003588 XMMRegister input_reg = ToDoubleRegister(instr->value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003589 static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
3590 static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003591
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003592 Label done, round_to_zero, below_one_half, do_not_compensate, restore;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003593 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003594 __ movq(kScratchRegister, one_half);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003595 __ movq(xmm_scratch, kScratchRegister);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003596 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003597 __ j(above, &below_one_half, Label::kNear);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003598
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003599 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3600 __ addsd(xmm_scratch, input_reg);
3601 __ cvttsd2si(output_reg, xmm_scratch);
3602 // Overflow is signalled with minint.
3603 __ cmpl(output_reg, Immediate(0x80000000));
3604 __ RecordComment("D2I conversion overflow");
3605 DeoptimizeIf(equal, instr->environment());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003606 __ jmp(&done, dist);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003607
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003608 __ bind(&below_one_half);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003609 __ movq(kScratchRegister, minus_one_half);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003610 __ movq(xmm_scratch, kScratchRegister);
3611 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003612 __ j(below_equal, &round_to_zero, Label::kNear);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003613
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003614 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3615 // compare and compensate.
3616 __ movq(kScratchRegister, input_reg); // Back up input_reg.
3617 __ subsd(input_reg, xmm_scratch);
3618 __ cvttsd2si(output_reg, input_reg);
3619 // Catch minint due to overflow, and to prevent overflow when compensating.
3620 __ cmpl(output_reg, Immediate(0x80000000));
3621 __ RecordComment("D2I conversion overflow");
3622 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003623
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003624 __ Cvtlsi2sd(xmm_scratch, output_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003625 __ ucomisd(input_reg, xmm_scratch);
3626 __ j(equal, &restore, Label::kNear);
3627 __ subl(output_reg, Immediate(1));
3628 // No overflow because we already ruled out minint.
3629 __ bind(&restore);
3630 __ movq(input_reg, kScratchRegister); // Restore input_reg.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003631 __ jmp(&done, dist);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003632
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003633 __ bind(&round_to_zero);
3634 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3635 // we can ignore the difference between a result of -0 and +0.
3636 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3637 __ movq(output_reg, input_reg);
3638 __ testq(output_reg, output_reg);
3639 __ RecordComment("Minus zero");
3640 DeoptimizeIf(negative, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003641 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003642 __ Set(output_reg, 0);
3643 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003644}
3645
3646
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003647void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003648 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003649 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3650 __ sqrtsd(input_reg, input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003651}
3652
3653
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003654void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003655 XMMRegister xmm_scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003656 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003657 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003658
3659 // Note that according to ECMA-262 15.8.2.13:
3660 // Math.pow(-Infinity, 0.5) == Infinity
3661 // Math.sqrt(-Infinity) == NaN
3662 Label done, sqrt;
3663 // Check base for -Infinity. According to IEEE-754, double-precision
3664 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003665 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003666 __ movq(xmm_scratch, kScratchRegister);
3667 __ ucomisd(xmm_scratch, input_reg);
3668 // Comparing -Infinity with NaN results in "unordered", which sets the
3669 // zero flag as if both were equal. However, it also sets the carry flag.
3670 __ j(not_equal, &sqrt, Label::kNear);
3671 __ j(carry, &sqrt, Label::kNear);
3672 // If input is -Infinity, return Infinity.
3673 __ xorps(input_reg, input_reg);
3674 __ subsd(input_reg, xmm_scratch);
3675 __ jmp(&done, Label::kNear);
3676
3677 // Square root.
3678 __ bind(&sqrt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003679 __ xorps(xmm_scratch, xmm_scratch);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003680 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
3681 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003682 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003683}
3684
3685
3686void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003687 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003688 // Having marked this as a call, we can use any registers.
3689 // Just make sure that the input/output registers are the expected ones.
3690
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003691 Register exponent = rdx;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003692 ASSERT(!instr->right()->IsRegister() ||
3693 ToRegister(instr->right()).is(exponent));
3694 ASSERT(!instr->right()->IsDoubleRegister() ||
3695 ToDoubleRegister(instr->right()).is(xmm1));
3696 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003697 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003698
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003699 if (exponent_type.IsSmi()) {
3700 MathPowStub stub(MathPowStub::TAGGED);
3701 __ CallStub(&stub);
3702 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003703 Label no_deopt;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003704 __ JumpIfSmi(exponent, &no_deopt, Label::kNear);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003705 __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003706 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003707 __ bind(&no_deopt);
3708 MathPowStub stub(MathPowStub::TAGGED);
3709 __ CallStub(&stub);
3710 } else if (exponent_type.IsInteger32()) {
3711 MathPowStub stub(MathPowStub::INTEGER);
3712 __ CallStub(&stub);
3713 } else {
3714 ASSERT(exponent_type.IsDouble());
3715 MathPowStub stub(MathPowStub::DOUBLE);
3716 __ CallStub(&stub);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003717 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003718}
3719
3720
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003721void LCodeGen::DoMathExp(LMathExp* instr) {
3722 XMMRegister input = ToDoubleRegister(instr->value());
3723 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003724 XMMRegister temp0 = double_scratch0();
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003725 Register temp1 = ToRegister(instr->temp1());
3726 Register temp2 = ToRegister(instr->temp2());
3727
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003728 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003729}
3730
3731
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003732void LCodeGen::DoMathLog(LMathLog* instr) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003733 ASSERT(instr->value()->Equals(instr->result()));
3734 XMMRegister input_reg = ToDoubleRegister(instr->value());
3735 XMMRegister xmm_scratch = double_scratch0();
3736 Label positive, done, zero;
3737 __ xorps(xmm_scratch, xmm_scratch);
3738 __ ucomisd(input_reg, xmm_scratch);
3739 __ j(above, &positive, Label::kNear);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003740 __ j(not_carry, &zero, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003741 ExternalReference nan =
3742 ExternalReference::address_of_canonical_non_hole_nan();
3743 Operand nan_operand = masm()->ExternalOperand(nan);
3744 __ movsd(input_reg, nan_operand);
3745 __ jmp(&done, Label::kNear);
3746 __ bind(&zero);
3747 ExternalReference ninf =
3748 ExternalReference::address_of_negative_infinity();
3749 Operand ninf_operand = masm()->ExternalOperand(ninf);
3750 __ movsd(input_reg, ninf_operand);
3751 __ jmp(&done, Label::kNear);
3752 __ bind(&positive);
3753 __ fldln2();
3754 __ subq(rsp, Immediate(kDoubleSize));
3755 __ movsd(Operand(rsp, 0), input_reg);
3756 __ fld_d(Operand(rsp, 0));
3757 __ fyl2x();
3758 __ fstp_d(Operand(rsp, 0));
3759 __ movsd(input_reg, Operand(rsp, 0));
3760 __ addq(rsp, Immediate(kDoubleSize));
3761 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003762}
3763
3764
danno@chromium.org160a7b02011-04-18 15:51:38 +00003765void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003766 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003767 ASSERT(ToRegister(instr->function()).is(rdi));
3768 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003769
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003770 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3771 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003772 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003773 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3774 ParameterCount count(instr->arity());
3775 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003776 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003777 CallKnownFunction(known_function,
3778 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003779 instr->arity(),
3780 instr,
3781 CALL_AS_METHOD,
3782 RDI_CONTAINS_TARGET);
3783 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003784}
3785
3786
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003787void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003788 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003789 ASSERT(ToRegister(instr->key()).is(rcx));
3790 ASSERT(ToRegister(instr->result()).is(rax));
3791
3792 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003793 Handle<Code> ic =
3794 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003795 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003796}
3797
3798
3799void LCodeGen::DoCallNamed(LCallNamed* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003800 ASSERT(ToRegister(instr->context()).is(rsi));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003801 ASSERT(ToRegister(instr->result()).is(rax));
3802
3803 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003804 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3805 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003806 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003807 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003808 CallCode(ic, mode, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003809}
3810
3811
3812void LCodeGen::DoCallFunction(LCallFunction* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003813 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003814 ASSERT(ToRegister(instr->function()).is(rdi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003815 ASSERT(ToRegister(instr->result()).is(rax));
3816
3817 int arity = instr->arity();
rossberg@chromium.org9ed27462014-01-07 14:16:41 +00003818 CallFunctionFlags flags =
3819 instr->hydrogen()->IsContextualCall() ?
3820 RECEIVER_IS_IMPLICIT : NO_CALL_FUNCTION_FLAGS;
3821 CallFunctionStub stub(arity, flags);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00003822 if (instr->hydrogen()->IsTailCall()) {
3823 if (NeedsEagerFrame()) __ leave();
3824 __ jmp(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
3825 } else {
3826 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
3827 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003828}
3829
3830
3831void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003832 ASSERT(ToRegister(instr->context()).is(rsi));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003833 ASSERT(ToRegister(instr->result()).is(rax));
3834 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003835 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3836 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003837 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003838 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003839 CallCode(ic, mode, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003840}
3841
3842
3843void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003844 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003845 CallKnownFunction(instr->hydrogen()->target(),
3846 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003847 instr->arity(),
3848 instr,
3849 CALL_AS_FUNCTION,
3850 RDI_UNINITIALIZED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003851}
3852
3853
3854void LCodeGen::DoCallNew(LCallNew* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003855 ASSERT(ToRegister(instr->context()).is(rsi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003856 ASSERT(ToRegister(instr->constructor()).is(rdi));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003857 ASSERT(ToRegister(instr->result()).is(rax));
3858
ager@chromium.org378b34e2011-01-28 08:04:38 +00003859 __ Set(rax, instr->arity());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003860 // No cell in ebx for construct type feedback in optimized code
3861 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
3862 __ Move(rbx, undefined_value);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003863 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003864 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003865}
3866
3867
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003868void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003869 ASSERT(ToRegister(instr->context()).is(rsi));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003870 ASSERT(ToRegister(instr->constructor()).is(rdi));
3871 ASSERT(ToRegister(instr->result()).is(rax));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003872
3873 __ Set(rax, instr->arity());
3874 __ Move(rbx, instr->hydrogen()->property_cell());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003875 ElementsKind kind = instr->hydrogen()->elements_kind();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003876 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00003877 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003878 ? DISABLE_ALLOCATION_SITES
3879 : DONT_OVERRIDE;
3880 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003881
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003882 if (instr->arity() == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003883 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003884 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3885 } else if (instr->arity() == 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00003886 Label done;
3887 if (IsFastPackedElementsKind(kind)) {
3888 Label packed_case;
3889 // We might need a change here
3890 // look at the first argument
3891 __ movq(rcx, Operand(rsp, 0));
3892 __ testq(rcx, rcx);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003893 __ j(zero, &packed_case, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00003894
3895 ElementsKind holey_kind = GetHoleyElementsKind(kind);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003896 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
3897 override_mode);
danno@chromium.org41728482013-06-12 22:31:22 +00003898 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003899 __ jmp(&done, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00003900 __ bind(&packed_case);
3901 }
3902
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003903 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003904 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.org41728482013-06-12 22:31:22 +00003905 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003906 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003907 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003908 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3909 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003910}
3911
3912
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003913void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003914 ASSERT(ToRegister(instr->context()).is(rsi));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003915 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003916}
3917
3918
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003919void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
3920 Register function = ToRegister(instr->function());
3921 Register code_object = ToRegister(instr->code_object());
3922 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
3923 __ movq(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
3924}
3925
3926
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003927void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3928 Register result = ToRegister(instr->result());
3929 Register base = ToRegister(instr->base_object());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003930 if (instr->offset()->IsConstantOperand()) {
3931 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
3932 __ lea(result, Operand(base, ToInteger32(offset)));
3933 } else {
3934 Register offset = ToRegister(instr->offset());
3935 __ lea(result, Operand(base, offset, times_1, 0));
3936 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003937}
3938
3939
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003940void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003941 HStoreNamedField* hinstr = instr->hydrogen();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003942 Representation representation = instr->representation();
3943
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003944 HObjectAccess access = hinstr->access();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003945 int offset = access.offset();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003946
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003947 if (access.IsExternalMemory()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003948 ASSERT(!hinstr->NeedsWriteBarrier());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003949 Register value = ToRegister(instr->value());
3950 if (instr->object()->IsConstantOperand()) {
3951 ASSERT(value.is(rax));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003952 ASSERT(!access.representation().IsSpecialization());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003953 LConstantOperand* object = LConstantOperand::cast(instr->object());
3954 __ store_rax(ToExternalReference(object));
3955 } else {
3956 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003957 __ Store(MemOperand(object, offset), value, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003958 }
3959 return;
3960 }
3961
3962 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003963 Handle<Map> transition = instr->transition();
3964
danno@chromium.orgf005df62013-04-30 16:36:45 +00003965 if (FLAG_track_fields && representation.IsSmi()) {
3966 if (instr->value()->IsConstantOperand()) {
3967 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003968 if (!IsInteger32Constant(operand_value) &&
3969 !IsSmiConstant(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003970 DeoptimizeIf(no_condition, instr->environment());
3971 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003972 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003973 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
3974 if (instr->value()->IsConstantOperand()) {
3975 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
3976 if (IsInteger32Constant(operand_value)) {
3977 DeoptimizeIf(no_condition, instr->environment());
3978 }
3979 } else {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003980 if (!hinstr->value()->type().IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003981 Register value = ToRegister(instr->value());
3982 Condition cc = masm()->CheckSmi(value);
3983 DeoptimizeIf(cc, instr->environment());
3984 }
3985 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003986 } else if (FLAG_track_double_fields && representation.IsDouble()) {
3987 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003988 ASSERT(access.IsInobject());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003989 ASSERT(!hinstr->NeedsWriteBarrier());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003990 XMMRegister value = ToDoubleRegister(instr->value());
3991 __ movsd(FieldOperand(object, offset), value);
3992 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003993 }
3994
danno@chromium.orgf005df62013-04-30 16:36:45 +00003995 if (!transition.is_null()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003996 if (!hinstr->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003997 __ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003998 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003999 Register temp = ToRegister(instr->temp());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004000 __ Move(kScratchRegister, transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00004001 __ movq(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister);
4002 // Update the write barrier for the map field.
4003 __ RecordWriteField(object,
4004 HeapObject::kMapOffset,
4005 kScratchRegister,
4006 temp,
4007 kSaveFPRegs,
4008 OMIT_REMEMBERED_SET,
4009 OMIT_SMI_CHECK);
4010 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00004011 }
4012
4013 // Do the store.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004014 SmiCheck check_needed = hinstr->value()->IsHeapObject()
4015 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004016
4017 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004018 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004019 write_register = ToRegister(instr->temp());
4020 __ movq(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
4021 }
4022
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004023 if (representation.IsSmi() &&
4024 hinstr->value()->representation().IsInteger32()) {
4025 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
4026 // Store int value directly to upper half of the smi.
4027 STATIC_ASSERT(kSmiTag == 0);
4028 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
4029 offset += kPointerSize / 2;
4030 representation = Representation::Integer32();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004031 }
4032
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004033 Operand operand = FieldOperand(write_register, offset);
4034
4035 if (instr->value()->IsRegister()) {
4036 Register value = ToRegister(instr->value());
4037 __ Store(operand, value, representation);
4038 } else {
4039 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4040 if (IsInteger32Constant(operand_value)) {
4041 ASSERT(!hinstr->NeedsWriteBarrier());
4042 int32_t value = ToInteger32(operand_value);
4043 if (representation.IsSmi()) {
4044 __ Move(operand, Smi::FromInt(value));
4045
4046 } else {
4047 __ movl(operand, Immediate(value));
4048 }
4049
4050 } else {
4051 Handle<Object> handle_value = ToHandle(operand_value);
4052 ASSERT(!hinstr->NeedsWriteBarrier());
4053 __ Move(operand, handle_value);
4054 }
4055 }
4056
4057 if (hinstr->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004058 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004059 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004060 // Update the write barrier for the object for in-object properties.
4061 __ RecordWriteField(write_register,
4062 offset,
4063 value,
4064 temp,
4065 kSaveFPRegs,
4066 EMIT_REMEMBERED_SET,
4067 check_needed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004068 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004069}
4070
4071
4072void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004073 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004074 ASSERT(ToRegister(instr->object()).is(rdx));
4075 ASSERT(ToRegister(instr->value()).is(rax));
4076
4077 __ Move(rcx, instr->hydrogen()->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004078 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004079 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4080 : isolate()->builtins()->StoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004081 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4082}
4083
4084
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004085void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
4086 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4087 Label done;
4088 __ j(NegateCondition(cc), &done, Label::kNear);
4089 __ int3();
4090 __ bind(&done);
4091 } else {
4092 DeoptimizeIf(cc, check->environment());
4093 }
4094}
4095
4096
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004097void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004098 if (instr->hydrogen()->skip_check()) return;
4099
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004100 if (instr->length()->IsRegister()) {
4101 Register reg = ToRegister(instr->length());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004102 if (!instr->hydrogen()->length()->representation().IsSmi()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004103 __ AssertZeroExtended(reg);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004104 }
4105 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004106 int32_t constant_index =
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004107 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004108 if (instr->hydrogen()->length()->representation().IsSmi()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004109 __ Cmp(reg, Smi::FromInt(constant_index));
4110 } else {
4111 __ cmpq(reg, Immediate(constant_index));
4112 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004113 } else {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004114 Register reg2 = ToRegister(instr->index());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004115 if (!instr->hydrogen()->index()->representation().IsSmi()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004116 __ AssertZeroExtended(reg2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004117 }
4118 __ cmpq(reg, reg2);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004119 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004120 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004121 Operand length = ToOperand(instr->length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004122 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004123 int32_t constant_index =
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004124 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004125 if (instr->hydrogen()->length()->representation().IsSmi()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004126 __ Cmp(length, Smi::FromInt(constant_index));
4127 } else {
4128 __ cmpq(length, Immediate(constant_index));
4129 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004130 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004131 __ cmpq(length, ToRegister(instr->index()));
danno@chromium.orgb6451162011-08-17 14:33:23 +00004132 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004133 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004134 Condition condition =
4135 instr->hydrogen()->allow_equality() ? below : below_equal;
4136 ApplyCheckIf(condition, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004137}
4138
4139
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004140void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4141 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004142 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004143 if (!key->IsConstantOperand()) {
4144 Register key_reg = ToRegister(key);
4145 // Even though the HLoad/StoreKeyedFastElement instructions force
4146 // the input representation for the key to be an integer, the input
4147 // gets replaced during bound check elimination with the index
4148 // argument to the bounds check, which can be tagged, so that case
4149 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004150 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004151 // Sign extend key because it could be a 32 bit negative value
4152 // and the dehoisted address computation happens in 64 bits
4153 __ movsxlq(key_reg, key_reg);
4154 }
4155 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004156 Operand operand(BuildFastArrayOperand(
4157 instr->elements(),
4158 key,
4159 elements_kind,
4160 0,
4161 instr->additional_index()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004162
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004163 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4164 XMMRegister value(ToDoubleRegister(instr->value()));
4165 __ cvtsd2ss(value, value);
4166 __ movss(operand, value);
4167 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
4168 __ movsd(operand, ToDoubleRegister(instr->value()));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004169 } else {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004170 Register value(ToRegister(instr->value()));
4171 switch (elements_kind) {
4172 case EXTERNAL_PIXEL_ELEMENTS:
4173 case EXTERNAL_BYTE_ELEMENTS:
4174 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4175 __ movb(operand, value);
4176 break;
4177 case EXTERNAL_SHORT_ELEMENTS:
4178 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4179 __ movw(operand, value);
4180 break;
4181 case EXTERNAL_INT_ELEMENTS:
4182 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4183 __ movl(operand, value);
4184 break;
4185 case EXTERNAL_FLOAT_ELEMENTS:
4186 case EXTERNAL_DOUBLE_ELEMENTS:
4187 case FAST_ELEMENTS:
4188 case FAST_SMI_ELEMENTS:
4189 case FAST_DOUBLE_ELEMENTS:
4190 case FAST_HOLEY_ELEMENTS:
4191 case FAST_HOLEY_SMI_ELEMENTS:
4192 case FAST_HOLEY_DOUBLE_ELEMENTS:
4193 case DICTIONARY_ELEMENTS:
4194 case NON_STRICT_ARGUMENTS_ELEMENTS:
4195 UNREACHABLE();
4196 break;
4197 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004198 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004199}
4200
4201
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004202void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004203 XMMRegister value = ToDoubleRegister(instr->value());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004204 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004205 if (!key->IsConstantOperand()) {
4206 Register key_reg = ToRegister(key);
4207 // Even though the HLoad/StoreKeyedFastElement instructions force
4208 // the input representation for the key to be an integer, the
4209 // input gets replaced during bound check elimination with the index
4210 // argument to the bounds check, which can be tagged, so that case
4211 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004212 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004213 // Sign extend key because it could be a 32 bit negative value
4214 // and the dehoisted address computation happens in 64 bits
4215 __ movsxlq(key_reg, key_reg);
4216 }
4217 }
4218
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004219 if (instr->NeedsCanonicalization()) {
4220 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004221
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004222 __ ucomisd(value, value);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004223 __ j(parity_odd, &have_value, Label::kNear); // NaN.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004224
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004225 __ Set(kScratchRegister, BitCast<uint64_t>(
4226 FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
4227 __ movq(value, kScratchRegister);
4228
4229 __ bind(&have_value);
4230 }
4231
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004232 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004233 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004234 key,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004235 FAST_DOUBLE_ELEMENTS,
4236 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4237 instr->additional_index());
4238
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004239 __ movsd(double_store_operand, value);
4240}
4241
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004242
4243void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004244 HStoreKeyed* hinstr = instr->hydrogen();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004245 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004246 if (!key->IsConstantOperand()) {
4247 Register key_reg = ToRegister(key);
4248 // Even though the HLoad/StoreKeyedFastElement instructions force
4249 // the input representation for the key to be an integer, the
4250 // input gets replaced during bound check elimination with the index
4251 // argument to the bounds check, which can be tagged, so that case
4252 // must be handled here, too.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004253 if (hinstr->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004254 // Sign extend key because it could be a 32 bit negative value
4255 // and the dehoisted address computation happens in 64 bits
4256 __ movsxlq(key_reg, key_reg);
4257 }
4258 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004259
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004260 int offset = FixedArray::kHeaderSize - kHeapObjectTag;
4261 Representation representation = hinstr->value()->representation();
4262
4263 if (representation.IsInteger32()) {
4264 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
4265 ASSERT(hinstr->elements_kind() == FAST_SMI_ELEMENTS);
4266 // Store int value directly to upper half of the smi.
4267 STATIC_ASSERT(kSmiTag == 0);
4268 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
4269 offset += kPointerSize / 2;
4270 }
4271
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004272 Operand operand =
4273 BuildFastArrayOperand(instr->elements(),
4274 key,
4275 FAST_ELEMENTS,
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004276 offset,
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004277 instr->additional_index());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004278
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004279 if (instr->value()->IsRegister()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004280 __ Store(operand, ToRegister(instr->value()), representation);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004281 } else {
4282 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4283 if (IsInteger32Constant(operand_value)) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004284 int32_t value = ToInteger32(operand_value);
4285 if (representation.IsSmi()) {
4286 __ Move(operand, Smi::FromInt(value));
4287
4288 } else {
4289 __ movl(operand, Immediate(value));
4290 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004291 } else {
4292 Handle<Object> handle_value = ToHandle(operand_value);
4293 __ Move(operand, handle_value);
4294 }
4295 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004296
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004297 if (hinstr->NeedsWriteBarrier()) {
4298 Register elements = ToRegister(instr->elements());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004299 ASSERT(instr->value()->IsRegister());
4300 Register value = ToRegister(instr->value());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004301 ASSERT(!key->IsConstantOperand());
4302 SmiCheck check_needed = hinstr->value()->IsHeapObject()
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004303 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004304 // Compute address of modified element and store it into key register.
4305 Register key_reg(ToRegister(key));
4306 __ lea(key_reg, operand);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004307 __ RecordWrite(elements,
4308 key_reg,
4309 value,
4310 kSaveFPRegs,
4311 EMIT_REMEMBERED_SET,
4312 check_needed);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004313 }
4314}
4315
4316
4317void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4318 if (instr->is_external()) {
4319 DoStoreKeyedExternalArray(instr);
4320 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4321 DoStoreKeyedFixedDoubleArray(instr);
4322 } else {
4323 DoStoreKeyedFixedArray(instr);
4324 }
4325}
4326
4327
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004328void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004329 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004330 ASSERT(ToRegister(instr->object()).is(rdx));
4331 ASSERT(ToRegister(instr->key()).is(rcx));
4332 ASSERT(ToRegister(instr->value()).is(rax));
4333
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004334 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004335 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4336 : isolate()->builtins()->KeyedStoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004337 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4338}
4339
4340
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004341void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4342 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004343
4344 Handle<Map> from_map = instr->original_map();
4345 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004346 ElementsKind from_kind = instr->from_kind();
4347 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004348
4349 Label not_applicable;
4350 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
4351 __ j(not_equal, &not_applicable);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004352 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004353 Register new_map_reg = ToRegister(instr->new_map_temp());
4354 __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
4356 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004357 ASSERT_NE(instr->temp(), NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004358 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004359 ToRegister(instr->temp()), kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004360 } else {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00004361 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004362 PushSafepointRegistersScope scope(this);
4363 if (!object_reg.is(rax)) {
4364 __ movq(rax, object_reg);
4365 }
4366 __ Move(rbx, to_map);
4367 TransitionElementsKindStub stub(from_kind, to_kind);
4368 __ CallStub(&stub);
4369 RecordSafepointWithRegisters(
4370 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004371 }
4372 __ bind(&not_applicable);
4373}
4374
4375
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004376void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4377 Register object = ToRegister(instr->object());
4378 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004379 Label no_memento_found;
4380 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004381 DeoptimizeIf(equal, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004382 __ bind(&no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004383}
4384
4385
danno@chromium.org160a7b02011-04-18 15:51:38 +00004386void LCodeGen::DoStringAdd(LStringAdd* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004387 ASSERT(ToRegister(instr->context()).is(rsi));
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004388 if (FLAG_new_string_add) {
4389 ASSERT(ToRegister(instr->left()).is(rdx));
4390 ASSERT(ToRegister(instr->right()).is(rax));
4391 NewStringAddStub stub(instr->hydrogen()->flags(),
4392 isolate()->heap()->GetPretenureMode());
4393 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4394 } else {
4395 EmitPushTaggedOperand(instr->left());
4396 EmitPushTaggedOperand(instr->right());
4397 StringAddStub stub(instr->hydrogen()->flags());
4398 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4399 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00004400}
4401
4402
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004403void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004404 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004405 public:
4406 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4407 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004408 virtual void Generate() V8_OVERRIDE {
4409 codegen()->DoDeferredStringCharCodeAt(instr_);
4410 }
4411 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004412 private:
4413 LStringCharCodeAt* instr_;
4414 };
4415
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004416 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004417 new(zone()) DeferredStringCharCodeAt(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004418
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004419 StringCharLoadGenerator::Generate(masm(),
4420 ToRegister(instr->string()),
4421 ToRegister(instr->index()),
4422 ToRegister(instr->result()),
4423 deferred->entry());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004424 __ bind(deferred->exit());
4425}
4426
4427
4428void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4429 Register string = ToRegister(instr->string());
4430 Register result = ToRegister(instr->result());
4431
4432 // TODO(3095996): Get rid of this. For now, we need to make the
4433 // result register contain a valid pointer because it is already
4434 // contained in the register pointer map.
4435 __ Set(result, 0);
4436
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004437 PushSafepointRegistersScope scope(this);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004438 __ push(string);
4439 // Push the index as a smi. This is safe because of the checks in
4440 // DoStringCharCodeAt above.
4441 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4442 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004443 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004444 __ Push(Smi::FromInt(const_index));
4445 } else {
4446 Register index = ToRegister(instr->index());
4447 __ Integer32ToSmi(index, index);
4448 __ push(index);
4449 }
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004450 CallRuntimeFromDeferred(
4451 Runtime::kStringCharCodeAt, 2, instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004452 __ AssertSmi(rax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004453 __ SmiToInteger32(rax, rax);
4454 __ StoreToSafepointRegisterSlot(result, rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004455}
4456
4457
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004458void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004459 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004460 public:
4461 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4462 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004463 virtual void Generate() V8_OVERRIDE {
4464 codegen()->DoDeferredStringCharFromCode(instr_);
4465 }
4466 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004467 private:
4468 LStringCharFromCode* instr_;
4469 };
4470
4471 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004472 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004473
4474 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4475 Register char_code = ToRegister(instr->char_code());
4476 Register result = ToRegister(instr->result());
4477 ASSERT(!char_code.is(result));
4478
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004479 __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004480 __ j(above, deferred->entry());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004481 __ movsxlq(char_code, char_code);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004482 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4483 __ movq(result, FieldOperand(result,
4484 char_code, times_pointer_size,
4485 FixedArray::kHeaderSize));
4486 __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
4487 __ j(equal, deferred->entry());
4488 __ bind(deferred->exit());
4489}
4490
4491
4492void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4493 Register char_code = ToRegister(instr->char_code());
4494 Register result = ToRegister(instr->result());
4495
4496 // TODO(3095996): Get rid of this. For now, we need to make the
4497 // result register contain a valid pointer because it is already
4498 // contained in the register pointer map.
4499 __ Set(result, 0);
4500
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004501 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004502 __ Integer32ToSmi(char_code, char_code);
4503 __ push(char_code);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004504 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004505 __ StoreToSafepointRegisterSlot(result, rax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004506}
4507
4508
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004509void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004510 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004511 ASSERT(input->IsRegister() || input->IsStackSlot());
4512 LOperand* output = instr->result();
4513 ASSERT(output->IsDoubleRegister());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004514 if (input->IsRegister()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004515 __ Cvtlsi2sd(ToDoubleRegister(output), ToRegister(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004516 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004517 __ Cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004518 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004519}
4520
4521
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004522void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4523 LOperand* input = instr->value();
4524 ASSERT(input->IsRegister());
4525 LOperand* output = instr->result();
4526 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4527 if (!instr->hydrogen()->value()->HasRange() ||
4528 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4529 DeoptimizeIf(overflow, instr->environment());
4530 }
4531}
4532
4533
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004534void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004535 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004536 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004537 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004538
4539 __ LoadUint32(ToDoubleRegister(output),
4540 ToRegister(input),
4541 ToDoubleRegister(temp));
4542}
4543
4544
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00004545void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4546 LOperand* input = instr->value();
4547 ASSERT(input->IsRegister());
4548 LOperand* output = instr->result();
4549 if (!instr->hydrogen()->value()->HasRange() ||
4550 !instr->hydrogen()->value()->range()->IsInSmiRange() ||
4551 instr->hydrogen()->value()->range()->upper() == kMaxInt) {
4552 // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
4553 // interval, so we treat kMaxInt as a sentinel for this entire interval.
4554 __ testl(ToRegister(input), Immediate(0x80000000));
4555 DeoptimizeIf(not_zero, instr->environment());
4556 }
4557 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4558}
4559
4560
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004561void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004562 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004563 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4564 Register reg = ToRegister(input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004565
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004566 __ Integer32ToSmi(reg, reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004567}
4568
4569
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004570void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004571 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004572 public:
4573 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4574 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004575 virtual void Generate() V8_OVERRIDE {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004576 codegen()->DoDeferredNumberTagU(instr_);
4577 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004578 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004579 private:
4580 LNumberTagU* instr_;
4581 };
4582
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004583 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004584 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4585 Register reg = ToRegister(input);
4586
4587 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4588 __ cmpl(reg, Immediate(Smi::kMaxValue));
4589 __ j(above, deferred->entry());
4590 __ Integer32ToSmi(reg, reg);
4591 __ bind(deferred->exit());
4592}
4593
4594
4595void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) {
4596 Label slow;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004597 Register reg = ToRegister(instr->value());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004598 Register tmp = reg.is(rax) ? rcx : rax;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004599 XMMRegister temp_xmm = ToDoubleRegister(instr->temp());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004600
4601 // Preserve the value of all registers.
4602 PushSafepointRegistersScope scope(this);
4603
4604 Label done;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004605 // Load value into temp_xmm which will be preserved across potential call to
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004606 // runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable
4607 // XMM registers on x64).
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004608 XMMRegister xmm_scratch = double_scratch0();
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004609 __ LoadUint32(temp_xmm, reg, xmm_scratch);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004610
4611 if (FLAG_inline_new) {
4612 __ AllocateHeapNumber(reg, tmp, &slow);
4613 __ jmp(&done, Label::kNear);
4614 }
4615
4616 // Slow case: Call the runtime system to do the number allocation.
4617 __ bind(&slow);
4618
4619 // Put a valid pointer value in the stack slot where the result
4620 // register is stored, as this register is in the pointer map, but contains an
4621 // integer value.
4622 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
4623
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004624 // NumberTagU uses the context from the frame, rather than
4625 // the environment's HContext or HInlinedContext value.
4626 // They only call Runtime::kAllocateHeapNumber.
4627 // The corresponding HChange instructions are added in a phase that does
4628 // not have easy access to the local context.
4629 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4630 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4631 RecordSafepointWithRegisters(
4632 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4633
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004634 if (!reg.is(rax)) __ movq(reg, rax);
4635
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004636 // Done. Put the value in temp_xmm into the value of the allocated heap
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004637 // number.
4638 __ bind(&done);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004639 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004640 __ StoreToSafepointRegisterSlot(reg, reg);
4641}
4642
4643
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004644void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004645 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004646 public:
4647 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4648 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004649 virtual void Generate() V8_OVERRIDE {
4650 codegen()->DoDeferredNumberTagD(instr_);
4651 }
4652 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004653 private:
4654 LNumberTagD* instr_;
4655 };
4656
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004657 XMMRegister input_reg = ToDoubleRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004658 Register reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004659 Register tmp = ToRegister(instr->temp());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004660
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004661 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004662 if (FLAG_inline_new) {
4663 __ AllocateHeapNumber(reg, tmp, deferred->entry());
4664 } else {
4665 __ jmp(deferred->entry());
4666 }
4667 __ bind(deferred->exit());
4668 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004669}
4670
4671
4672void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004673 // TODO(3095996): Get rid of this. For now, we need to make the
4674 // result register contain a valid pointer because it is already
4675 // contained in the register pointer map.
4676 Register reg = ToRegister(instr->result());
4677 __ Move(reg, Smi::FromInt(0));
4678
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004679 {
4680 PushSafepointRegistersScope scope(this);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004681 // NumberTagD uses the context from the frame, rather than
4682 // the environment's HContext or HInlinedContext value.
4683 // They only call Runtime::kAllocateHeapNumber.
4684 // The corresponding HChange instructions are added in a phase that does
4685 // not have easy access to the local context.
4686 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4687 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4688 RecordSafepointWithRegisters(
4689 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004690 __ movq(kScratchRegister, rax);
4691 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004692 __ movq(reg, kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004693}
4694
4695
4696void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004697 ASSERT(instr->value()->Equals(instr->result()));
4698 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004699 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4700 __ Integer32ToSmi(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004701}
4702
4703
4704void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004705 ASSERT(instr->value()->Equals(instr->result()));
4706 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004707 if (instr->needs_check()) {
4708 Condition is_smi = __ CheckSmi(input);
4709 DeoptimizeIf(NegateCondition(is_smi), instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004710 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004711 __ AssertSmi(input);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004712 }
4713 __ SmiToInteger32(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004714}
4715
4716
4717void LCodeGen::EmitNumberUntagD(Register input_reg,
4718 XMMRegister result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004719 bool can_convert_undefined_to_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004720 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004721 LEnvironment* env,
4722 NumberUntagDMode mode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004723 Label convert, load_smi, done;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004724
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004725 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004726 // Smi check.
4727 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004728
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004729 // Heap number map check.
4730 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4731 Heap::kHeapNumberMapRootIndex);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00004732
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004733 // On x64 it is safe to load at heap number offset before evaluating the map
4734 // check, since all heap objects are at least two words long.
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004735 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004736
4737 if (can_convert_undefined_to_nan) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004738 __ j(not_equal, &convert, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004739 } else {
4740 DeoptimizeIf(not_equal, env);
4741 }
4742
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004743 if (deoptimize_on_minus_zero) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004744 XMMRegister xmm_scratch = double_scratch0();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004745 __ xorps(xmm_scratch, xmm_scratch);
4746 __ ucomisd(xmm_scratch, result_reg);
4747 __ j(not_equal, &done, Label::kNear);
4748 __ movmskpd(kScratchRegister, result_reg);
4749 __ testq(kScratchRegister, Immediate(1));
4750 DeoptimizeIf(not_zero, env);
4751 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004752 __ jmp(&done, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004753
4754 if (can_convert_undefined_to_nan) {
4755 __ bind(&convert);
4756
4757 // Convert undefined (and hole) to NaN. Compute NaN as 0/0.
4758 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
4759 DeoptimizeIf(not_equal, env);
4760
4761 __ xorps(result_reg, result_reg);
4762 __ divsd(result_reg, result_reg);
4763 __ jmp(&done, Label::kNear);
4764 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004765 } else {
4766 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004767 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004768
4769 // Smi to XMM conversion
4770 __ bind(&load_smi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004771 __ SmiToInteger32(kScratchRegister, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004772 __ Cvtlsi2sd(result_reg, kScratchRegister);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004773 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004774}
4775
4776
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004777void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004778 Register input_reg = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004779
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004780 if (instr->truncating()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004781 Label no_heap_number, check_bools, check_false;
4782
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004783 // Heap number map check.
4784 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4785 Heap::kHeapNumberMapRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004786 __ j(not_equal, &no_heap_number, Label::kNear);
4787 __ TruncateHeapNumberToI(input_reg, input_reg);
4788 __ jmp(done);
4789
4790 __ bind(&no_heap_number);
4791 // Check for Oddballs. Undefined/False is converted to zero and True to one
4792 // for truncating conversions.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004793 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004794 __ j(not_equal, &check_bools, Label::kNear);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004795 __ Set(input_reg, 0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004796 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004797
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004798 __ bind(&check_bools);
4799 __ CompareRoot(input_reg, Heap::kTrueValueRootIndex);
4800 __ j(not_equal, &check_false, Label::kNear);
4801 __ Set(input_reg, 1);
4802 __ jmp(done);
4803
4804 __ bind(&check_false);
4805 __ CompareRoot(input_reg, Heap::kFalseValueRootIndex);
4806 __ RecordComment("Deferred TaggedToI: cannot truncate");
4807 DeoptimizeIf(not_equal, instr->environment());
4808 __ Set(input_reg, 0);
4809 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004810 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004811 Label bailout;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004812 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004813 __ TaggedToI(input_reg, input_reg, xmm_temp,
4814 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4815
4816 __ jmp(done);
4817 __ bind(&bailout);
4818 DeoptimizeIf(no_condition, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004819 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004820}
4821
4822
4823void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004824 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 public:
4826 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4827 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004828 virtual void Generate() V8_OVERRIDE {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004829 codegen()->DoDeferredTaggedToI(instr_, done());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004830 }
4831 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004832 private:
4833 LTaggedToI* instr_;
4834 };
4835
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004836 LOperand* input = instr->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004837 ASSERT(input->IsRegister());
4838 ASSERT(input->Equals(instr->result()));
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004839 Register input_reg = ToRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004840
4841 if (instr->hydrogen()->value()->representation().IsSmi()) {
4842 __ SmiToInteger32(input_reg, input_reg);
4843 } else {
4844 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
4845 __ JumpIfNotSmi(input_reg, deferred->entry());
4846 __ SmiToInteger32(input_reg, input_reg);
4847 __ bind(deferred->exit());
4848 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004849}
4850
4851
4852void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004853 LOperand* input = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004854 ASSERT(input->IsRegister());
4855 LOperand* result = instr->result();
4856 ASSERT(result->IsDoubleRegister());
4857
4858 Register input_reg = ToRegister(input);
4859 XMMRegister result_reg = ToDoubleRegister(result);
4860
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004861 HValue* value = instr->hydrogen()->value();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004862 NumberUntagDMode mode = value->representation().IsSmi()
4863 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004864
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004865 EmitNumberUntagD(input_reg, result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004866 instr->hydrogen()->can_convert_undefined_to_nan(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004867 instr->hydrogen()->deoptimize_on_minus_zero(),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004868 instr->environment(),
4869 mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004870}
4871
4872
4873void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004874 LOperand* input = instr->value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004875 ASSERT(input->IsDoubleRegister());
4876 LOperand* result = instr->result();
4877 ASSERT(result->IsRegister());
4878
4879 XMMRegister input_reg = ToDoubleRegister(input);
4880 Register result_reg = ToRegister(result);
4881
4882 if (instr->truncating()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004883 __ TruncateDoubleToI(result_reg, input_reg);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004884 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004885 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004886 XMMRegister xmm_scratch = double_scratch0();
4887 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004888 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4889
4890 __ jmp(&done, Label::kNear);
4891 __ bind(&bailout);
4892 DeoptimizeIf(no_condition, instr->environment());
4893 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004894 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004895}
4896
4897
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004898void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4899 LOperand* input = instr->value();
4900 ASSERT(input->IsDoubleRegister());
4901 LOperand* result = instr->result();
4902 ASSERT(result->IsRegister());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004903
4904 XMMRegister input_reg = ToDoubleRegister(input);
4905 Register result_reg = ToRegister(result);
4906
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004907 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004908 XMMRegister xmm_scratch = double_scratch0();
4909 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004910 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004911
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004912 __ jmp(&done, Label::kNear);
4913 __ bind(&bailout);
4914 DeoptimizeIf(no_condition, instr->environment());
4915 __ bind(&done);
4916
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004917 __ Integer32ToSmi(result_reg, result_reg);
4918 DeoptimizeIf(overflow, instr->environment());
4919}
4920
4921
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004922void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004923 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004924 Condition cc = masm()->CheckSmi(ToRegister(input));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004925 DeoptimizeIf(NegateCondition(cc), instr->environment());
4926}
4927
4928
4929void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004930 if (!instr->hydrogen()->value()->IsHeapObject()) {
4931 LOperand* input = instr->value();
4932 Condition cc = masm()->CheckSmi(ToRegister(input));
4933 DeoptimizeIf(cc, instr->environment());
4934 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004935}
4936
4937
4938void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004939 Register input = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004940
4941 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
4942
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004943 if (instr->hydrogen()->is_interval_check()) {
4944 InstanceType first;
4945 InstanceType last;
4946 instr->hydrogen()->GetCheckInterval(&first, &last);
4947
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004948 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4949 Immediate(static_cast<int8_t>(first)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004950
4951 // If there is only one type in the interval check for equality.
4952 if (first == last) {
4953 DeoptimizeIf(not_equal, instr->environment());
4954 } else {
4955 DeoptimizeIf(below, instr->environment());
4956 // Omit check for the last type.
4957 if (last != LAST_TYPE) {
4958 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4959 Immediate(static_cast<int8_t>(last)));
4960 DeoptimizeIf(above, instr->environment());
4961 }
4962 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004963 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004964 uint8_t mask;
4965 uint8_t tag;
4966 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4967
4968 if (IsPowerOf2(mask)) {
4969 ASSERT(tag == 0 || IsPowerOf2(tag));
4970 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4971 Immediate(mask));
4972 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4973 } else {
4974 __ movzxbl(kScratchRegister,
4975 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
4976 __ andb(kScratchRegister, Immediate(mask));
4977 __ cmpb(kScratchRegister, Immediate(tag));
4978 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004979 }
4980 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004981}
4982
4983
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004984void LCodeGen::DoCheckValue(LCheckValue* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004985 Register reg = ToRegister(instr->value());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004986 __ Cmp(reg, instr->hydrogen()->object().handle());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004987 DeoptimizeIf(not_equal, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004988}
4989
4990
danno@chromium.org59400602013-08-13 17:09:37 +00004991void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
4992 {
4993 PushSafepointRegistersScope scope(this);
4994 __ push(object);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004995 __ Set(rsi, 0);
4996 __ CallRuntimeSaveDoubles(Runtime::kMigrateInstance);
4997 RecordSafepointWithRegisters(
4998 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
4999
danno@chromium.org59400602013-08-13 17:09:37 +00005000 __ testq(rax, Immediate(kSmiTagMask));
5001 }
5002 DeoptimizeIf(zero, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005003}
5004
5005
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005006void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005007 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00005008 public:
5009 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
5010 : LDeferredCode(codegen), instr_(instr), object_(object) {
5011 SetExit(check_maps());
5012 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005013 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00005014 codegen()->DoDeferredInstanceMigration(instr_, object_);
5015 }
5016 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005017 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00005018 private:
5019 LCheckMaps* instr_;
5020 Label check_maps_;
5021 Register object_;
5022 };
5023
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005024 if (instr->hydrogen()->CanOmitMapChecks()) return;
danno@chromium.org59400602013-08-13 17:09:37 +00005025
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005026 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00005027 ASSERT(input->IsRegister());
5028 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005029
danno@chromium.org59400602013-08-13 17:09:37 +00005030 DeferredCheckMaps* deferred = NULL;
5031 if (instr->hydrogen()->has_migration_target()) {
5032 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
5033 __ bind(deferred->check_maps());
5034 }
5035
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005036 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005037 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005038 for (int i = 0; i < map_set.size() - 1; i++) {
5039 Handle<Map> map = map_set.at(i).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005040 __ CompareMap(reg, map);
5041 __ j(equal, &success, Label::kNear);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005042 }
danno@chromium.org59400602013-08-13 17:09:37 +00005043
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005044 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005045 __ CompareMap(reg, map);
danno@chromium.org59400602013-08-13 17:09:37 +00005046 if (instr->hydrogen()->has_migration_target()) {
5047 __ j(not_equal, deferred->entry());
5048 } else {
5049 DeoptimizeIf(not_equal, instr->environment());
5050 }
5051
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005052 __ bind(&success);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005053}
5054
5055
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005056void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5057 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005058 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005059 Register result_reg = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005060 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005061}
5062
5063
5064void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5065 ASSERT(instr->unclamped()->Equals(instr->result()));
5066 Register value_reg = ToRegister(instr->result());
5067 __ ClampUint8(value_reg);
5068}
5069
5070
5071void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5072 ASSERT(instr->unclamped()->Equals(instr->result()));
5073 Register input_reg = ToRegister(instr->unclamped());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005074 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005075 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005076 Label is_smi, done, heap_number;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005077 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
5078 __ JumpIfSmi(input_reg, &is_smi, dist);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005079
5080 // Check for heap number
5081 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5082 factory()->heap_number_map());
5083 __ j(equal, &heap_number, Label::kNear);
5084
5085 // Check for undefined. Undefined is converted to zero for clamping
5086 // conversions.
5087 __ Cmp(input_reg, factory()->undefined_value());
5088 DeoptimizeIf(not_equal, instr->environment());
5089 __ movq(input_reg, Immediate(0));
5090 __ jmp(&done, Label::kNear);
5091
5092 // Heap number
5093 __ bind(&heap_number);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005094 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
5095 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005096 __ jmp(&done, Label::kNear);
5097
5098 // smi
5099 __ bind(&is_smi);
5100 __ SmiToInteger32(input_reg, input_reg);
5101 __ ClampUint8(input_reg);
5102
5103 __ bind(&done);
5104}
5105
5106
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005107void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005108 class DeferredAllocate V8_FINAL : public LDeferredCode {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005109 public:
5110 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5111 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005112 virtual void Generate() V8_OVERRIDE {
5113 codegen()->DoDeferredAllocate(instr_);
5114 }
5115 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005116 private:
5117 LAllocate* instr_;
5118 };
5119
5120 DeferredAllocate* deferred =
5121 new(zone()) DeferredAllocate(this, instr);
5122
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005123 Register result = ToRegister(instr->result());
5124 Register temp = ToRegister(instr->temp());
5125
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005126 // Allocate memory for the object.
5127 AllocationFlags flags = TAG_OBJECT;
5128 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5129 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5130 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005131 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5132 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5133 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005134 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005135 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5136 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005137 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005138 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005139
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005140 if (instr->size()->IsConstantOperand()) {
5141 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005142 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005143 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005144 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005145 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005146 }
5147
5148 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005149
5150 if (instr->hydrogen()->MustPrefillWithFiller()) {
5151 if (instr->size()->IsConstantOperand()) {
5152 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5153 __ movl(temp, Immediate((size / kPointerSize) - 1));
5154 } else {
5155 temp = ToRegister(instr->size());
5156 __ sar(temp, Immediate(kPointerSizeLog2));
5157 __ decl(temp);
5158 }
5159 Label loop;
5160 __ bind(&loop);
5161 __ Move(FieldOperand(result, temp, times_pointer_size, 0),
5162 isolate()->factory()->one_pointer_filler_map());
5163 __ decl(temp);
5164 __ j(not_zero, &loop);
5165 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005166}
5167
5168
5169void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005170 Register result = ToRegister(instr->result());
5171
5172 // TODO(3095996): Get rid of this. For now, we need to make the
5173 // result register contain a valid pointer because it is already
5174 // contained in the register pointer map.
danno@chromium.orgf005df62013-04-30 16:36:45 +00005175 __ Move(result, Smi::FromInt(0));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005176
5177 PushSafepointRegistersScope scope(this);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005178 if (instr->size()->IsRegister()) {
5179 Register size = ToRegister(instr->size());
5180 ASSERT(!size.is(result));
5181 __ Integer32ToSmi(size, size);
5182 __ push(size);
5183 } else {
5184 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5185 __ Push(Smi::FromInt(size));
5186 }
5187
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005188 int flags = 0;
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005189 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5190 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5191 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005192 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005193 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5194 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005195 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005196 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005197 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005198 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005199 __ Push(Smi::FromInt(flags));
5200
5201 CallRuntimeFromDeferred(
5202 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005203 __ StoreToSafepointRegisterSlot(result, rax);
5204}
5205
5206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005208 ASSERT(ToRegister(instr->value()).is(rax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 __ push(rax);
5210 CallRuntime(Runtime::kToFastProperties, 1, instr);
5211}
5212
5213
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005214void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005215 ASSERT(ToRegister(instr->context()).is(rsi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005216 Label materialized;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005217 // Registers will be used as follows:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005218 // rcx = literals array.
5219 // rbx = regexp literal.
5220 // rax = regexp literal clone.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005221 int literal_offset =
5222 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005223 __ Move(rcx, instr->hydrogen()->literals());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005224 __ movq(rbx, FieldOperand(rcx, literal_offset));
5225 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005226 __ j(not_equal, &materialized, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005227
5228 // Create regexp literal using runtime function
5229 // Result will be in rax.
5230 __ push(rcx);
5231 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
5232 __ Push(instr->hydrogen()->pattern());
5233 __ Push(instr->hydrogen()->flags());
5234 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5235 __ movq(rbx, rax);
5236
5237 __ bind(&materialized);
5238 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5239 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005240 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005241 __ jmp(&allocated, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005242
5243 __ bind(&runtime_allocate);
5244 __ push(rbx);
5245 __ Push(Smi::FromInt(size));
5246 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5247 __ pop(rbx);
5248
5249 __ bind(&allocated);
5250 // Copy the content into the newly allocated memory.
5251 // (Unroll copy loop once for better throughput).
5252 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5253 __ movq(rdx, FieldOperand(rbx, i));
5254 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
5255 __ movq(FieldOperand(rax, i), rdx);
5256 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
5257 }
5258 if ((size % (2 * kPointerSize)) != 0) {
5259 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
5260 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
5261 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005262}
5263
5264
5265void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005266 ASSERT(ToRegister(instr->context()).is(rsi));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005267 // Use the fast case closure allocation code that allocates in new
5268 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005269 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005270 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5271 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5272 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005273 __ Move(rbx, instr->hydrogen()->shared_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005274 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005275 } else {
5276 __ push(rsi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005277 __ Push(instr->hydrogen()->shared_info());
5278 __ PushRoot(pretenure ? Heap::kTrueValueRootIndex :
5279 Heap::kFalseValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005280 CallRuntime(Runtime::kNewClosure, 3, instr);
5281 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005282}
5283
5284
5285void LCodeGen::DoTypeof(LTypeof* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005286 ASSERT(ToRegister(instr->context()).is(rsi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005287 LOperand* input = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00005288 EmitPushTaggedOperand(input);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005289 CallRuntime(Runtime::kTypeof, 1, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005290}
5291
5292
danno@chromium.org160a7b02011-04-18 15:51:38 +00005293void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
5294 ASSERT(!operand->IsDoubleRegister());
5295 if (operand->IsConstantOperand()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005296 __ Push(ToHandle(LConstantOperand::cast(operand)));
danno@chromium.org160a7b02011-04-18 15:51:38 +00005297 } else if (operand->IsRegister()) {
5298 __ push(ToRegister(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005299 } else {
danno@chromium.org160a7b02011-04-18 15:51:38 +00005300 __ push(ToOperand(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005301 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005302}
5303
5304
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005305void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005306 Register input = ToRegister(instr->value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005307 Condition final_branch_condition = EmitTypeofIs(instr, input);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005308 if (final_branch_condition != no_condition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005309 EmitBranch(instr, final_branch_condition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005310 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005311}
5312
5313
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005314Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
5315 Label* true_label = instr->TrueLabel(chunk_);
5316 Label* false_label = instr->FalseLabel(chunk_);
5317 Handle<String> type_name = instr->type_literal();
5318 int left_block = instr->TrueDestination(chunk_);
5319 int right_block = instr->FalseDestination(chunk_);
5320 int next_block = GetNextEmittedBlock();
5321
5322 Label::Distance true_distance = left_block == next_block ? Label::kNear
5323 : Label::kFar;
5324 Label::Distance false_distance = right_block == next_block ? Label::kNear
5325 : Label::kFar;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005326 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005327 if (type_name->Equals(heap()->number_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005328 __ JumpIfSmi(input, true_label, true_distance);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00005329 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
5330 Heap::kHeapNumberMapRootIndex);
5331
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005332 final_branch_condition = equal;
5333
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005334 } else if (type_name->Equals(heap()->string_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005335 __ JumpIfSmi(input, false_label, false_distance);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005336 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005337 __ j(above_equal, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005338 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5339 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005340 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005341
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005342 } else if (type_name->Equals(heap()->symbol_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005343 __ JumpIfSmi(input, false_label, false_distance);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005344 __ CmpObjectType(input, SYMBOL_TYPE, input);
5345 final_branch_condition = equal;
5346
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005347 } else if (type_name->Equals(heap()->boolean_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005348 __ CompareRoot(input, Heap::kTrueValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005349 __ j(equal, true_label, true_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005350 __ CompareRoot(input, Heap::kFalseValueRootIndex);
5351 final_branch_condition = equal;
5352
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005353 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005354 __ CompareRoot(input, Heap::kNullValueRootIndex);
5355 final_branch_condition = equal;
5356
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005357 } else if (type_name->Equals(heap()->undefined_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005358 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005359 __ j(equal, true_label, true_distance);
5360 __ JumpIfSmi(input, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005361 // Check for undetectable objects => true.
5362 __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
5363 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5364 Immediate(1 << Map::kIsUndetectable));
5365 final_branch_condition = not_zero;
5366
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005367 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005368 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005369 __ JumpIfSmi(input, false_label, false_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005370 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005371 __ j(equal, true_label, true_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005372 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5373 final_branch_condition = equal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005374
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005375 } else if (type_name->Equals(heap()->object_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005376 __ JumpIfSmi(input, false_label, false_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005377 if (!FLAG_harmony_typeof) {
5378 __ CompareRoot(input, Heap::kNullValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005379 __ j(equal, true_label, true_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005380 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005381 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005382 __ j(below, false_label, false_distance);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005383 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005384 __ j(above, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005385 // Check for undetectable objects => false.
5386 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5387 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005388 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005389
5390 } else {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005391 __ jmp(false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005392 }
5393
5394 return final_branch_condition;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005395}
5396
5397
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005398void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005399 Register temp = ToRegister(instr->temp());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005400
5401 EmitIsConstructCall(temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005402 EmitBranch(instr, equal);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005403}
5404
5405
5406void LCodeGen::EmitIsConstructCall(Register temp) {
5407 // Get the frame pointer for the calling frame.
5408 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
5409
5410 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005411 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005412 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5413 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005414 __ j(not_equal, &check_frame_marker, Label::kNear);
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005415 __ movq(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005416
5417 // Check the marker in the calling frame.
5418 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005419 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5420 Smi::FromInt(StackFrame::CONSTRUCT));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005421}
5422
5423
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005424void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005425 if (info()->IsStub()) return;
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005426 // Ensure that we have enough space after the previous lazy-bailout
5427 // instruction for patching the code here.
5428 int current_pc = masm()->pc_offset();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005429 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5430 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5431 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005432 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005433}
5434
5435
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005436void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005437 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5438 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005439 ASSERT(instr->HasEnvironment());
5440 LEnvironment* env = instr->environment();
5441 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5442 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005443}
5444
5445
5446void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005447 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5448 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5449 // needed return address), even though the implementation of LAZY and EAGER is
5450 // now identical. When LAZY is eventually completely folded into EAGER, remove
5451 // the special case below.
5452 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5453 type = Deoptimizer::LAZY;
danno@chromium.orgaefd6072013-05-14 14:11:47 +00005454 }
danno@chromium.org59400602013-08-13 17:09:37 +00005455
5456 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005457 DeoptimizeIf(no_condition, instr->environment(), type);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005458}
5459
5460
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005461void LCodeGen::DoDummy(LDummy* instr) {
5462 // Nothing to see here, move on!
5463}
5464
5465
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005466void LCodeGen::DoDummyUse(LDummyUse* instr) {
5467 // Nothing to see here, move on!
5468}
5469
5470
ager@chromium.org04921a82011-06-27 13:21:41 +00005471void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005472 PushSafepointRegistersScope scope(this);
5473 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
5474 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5475 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
5476 ASSERT(instr->HasEnvironment());
5477 LEnvironment* env = instr->environment();
5478 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005479}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005480
ager@chromium.org04921a82011-06-27 13:21:41 +00005481
5482void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005483 class DeferredStackCheck V8_FINAL : public LDeferredCode {
ager@chromium.org04921a82011-06-27 13:21:41 +00005484 public:
5485 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5486 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005487 virtual void Generate() V8_OVERRIDE {
5488 codegen()->DoDeferredStackCheck(instr_);
5489 }
5490 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005491 private:
5492 LStackCheck* instr_;
5493 };
5494
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005495 ASSERT(instr->HasEnvironment());
5496 LEnvironment* env = instr->environment();
5497 // There is no LLazyBailout instruction for stack-checks. We have to
5498 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005499 if (instr->hydrogen()->is_function_entry()) {
5500 // Perform stack overflow check.
5501 Label done;
5502 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5503 __ j(above_equal, &done, Label::kNear);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005504
5505 ASSERT(instr->context()->IsRegister());
5506 ASSERT(ToRegister(instr->context()).is(rsi));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005507 CallCode(isolate()->builtins()->StackCheck(),
5508 RelocInfo::CODE_TARGET,
5509 instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005510 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5511 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00005512 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005513 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5514 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005515 } else {
5516 ASSERT(instr->hydrogen()->is_backwards_branch());
5517 // Perform stack overflow check if this goto needs it before jumping.
5518 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005519 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005520 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5521 __ j(below, deferred_stack_check->entry());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005522 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5523 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00005524 __ bind(instr->done_label());
5525 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005526 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5527 // Don't record a deoptimization index for the safepoint here.
5528 // This will be done explicitly when emitting call and the safepoint in
5529 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005530 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005531}
5532
5533
5534void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005535 // This is a pseudo-instruction that ensures that the environment here is
5536 // properly registered for deoptimization and records the assembler's PC
5537 // offset.
5538 LEnvironment* environment = instr->environment();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005539
5540 // If the environment were already registered, we would have no way of
5541 // backpatching it with the spill slot operands.
5542 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005543 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005544
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005545 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005546}
5547
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005548
5549void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005550 ASSERT(ToRegister(instr->context()).is(rsi));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005551 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
5552 DeoptimizeIf(equal, instr->environment());
5553
5554 Register null_value = rdi;
5555 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5556 __ cmpq(rax, null_value);
5557 DeoptimizeIf(equal, instr->environment());
5558
5559 Condition cc = masm()->CheckSmi(rax);
5560 DeoptimizeIf(cc, instr->environment());
5561
5562 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5563 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
5564 DeoptimizeIf(below_equal, instr->environment());
5565
5566 Label use_cache, call_runtime;
5567 __ CheckEnumCache(null_value, &call_runtime);
5568
5569 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
5570 __ jmp(&use_cache, Label::kNear);
5571
5572 // Get the set of properties to enumerate.
5573 __ bind(&call_runtime);
5574 __ push(rax);
5575 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5576
5577 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
5578 Heap::kMetaMapRootIndex);
5579 DeoptimizeIf(not_equal, instr->environment());
5580 __ bind(&use_cache);
5581}
5582
5583
5584void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5585 Register map = ToRegister(instr->map());
5586 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005587 Label load_cache, done;
5588 __ EnumLength(result, map);
5589 __ Cmp(result, Smi::FromInt(0));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005590 __ j(not_equal, &load_cache, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005591 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005592 __ jmp(&done, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005593 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005594 __ LoadInstanceDescriptors(map, result);
5595 __ movq(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005596 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005597 __ movq(result,
5598 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005599 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005600 Condition cc = masm()->CheckSmi(result);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005601 DeoptimizeIf(cc, instr->environment());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005602}
5603
5604
5605void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5606 Register object = ToRegister(instr->value());
5607 __ cmpq(ToRegister(instr->map()),
5608 FieldOperand(object, HeapObject::kMapOffset));
5609 DeoptimizeIf(not_equal, instr->environment());
5610}
5611
5612
5613void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5614 Register object = ToRegister(instr->object());
5615 Register index = ToRegister(instr->index());
5616
5617 Label out_of_object, done;
5618 __ SmiToInteger32(index, index);
5619 __ cmpl(index, Immediate(0));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005620 __ j(less, &out_of_object, Label::kNear);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005621 __ movq(object, FieldOperand(object,
5622 index,
5623 times_pointer_size,
5624 JSObject::kHeaderSize));
5625 __ jmp(&done, Label::kNear);
5626
5627 __ bind(&out_of_object);
5628 __ movq(object, FieldOperand(object, JSObject::kPropertiesOffset));
5629 __ negl(index);
5630 // Index is now equal to out of object property index plus 1.
5631 __ movq(object, FieldOperand(object,
5632 index,
5633 times_pointer_size,
5634 FixedArray::kHeaderSize - kPointerSize));
5635 __ bind(&done);
5636}
5637
5638
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005639#undef __
5640
5641} } // namespace v8::internal
5642
5643#endif // V8_TARGET_ARCH_X64