blob: 7c70094fbf03cda94da80d04a01e604d2b42d75e [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
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000114bool LCodeGen::GeneratePrologue() {
115 ASSERT(is_generating());
116
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000117 if (info()->IsOptimizing()) {
118 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000119
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000120#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000121 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000122 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000123 __ int3();
124 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000125#endif
126
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000127 // Strict mode functions need to replace the receiver with undefined
128 // when called as functions (without an explicit receiver
129 // object). rcx is zero for method calls and non-zero for function
130 // calls.
131 if (!info_->is_classic_mode() || info_->is_native()) {
132 Label ok;
133 __ testq(rcx, rcx);
134 __ j(zero, &ok, Label::kNear);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000135 StackArgumentsAccessor args(rsp, scope()->num_parameters());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000136 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000137 __ movq(args.GetReceiverOperand(), kScratchRegister);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000138 __ bind(&ok);
139 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000140 }
141
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000142 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000143 if (NeedsEagerFrame()) {
144 ASSERT(!frame_is_built_);
145 frame_is_built_ = true;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000146 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000147 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000148 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000149
150 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000151 int slots = GetStackSlotCount();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000152 if (slots > 0) {
153 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000154 __ subq(rsp, Immediate(slots * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000155#ifdef _MSC_VER
156 MakeSureStackPagesMapped(slots * kPointerSize);
157#endif
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000158 __ push(rax);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000159 __ Set(rax, slots);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000160 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE64);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000161 Label loop;
162 __ bind(&loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000163 __ movq(MemOperand(rsp, rax, times_pointer_size, 0),
164 kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000165 __ decl(rax);
166 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000167 __ pop(rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000168 } else {
169 __ subq(rsp, Immediate(slots * kPointerSize));
170#ifdef _MSC_VER
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000171 MakeSureStackPagesMapped(slots * kPointerSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000172#endif
173 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000174
175 if (info()->saves_caller_doubles()) {
176 Comment(";;; Save clobbered callee double registers");
177 int count = 0;
178 BitVector* doubles = chunk()->allocated_double_registers();
179 BitVector::Iterator save_iterator(doubles);
180 while (!save_iterator.Done()) {
181 __ movsd(MemOperand(rsp, count * kDoubleSize),
182 XMMRegister::FromAllocationIndex(save_iterator.Current()));
183 save_iterator.Advance();
184 count++;
185 }
186 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000187 }
188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000189 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000190 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000191 if (heap_slots > 0) {
192 Comment(";;; Allocate local context");
193 // Argument to NewContext is the function, which is still in rdi.
194 __ push(rdi);
195 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
196 FastNewContextStub stub(heap_slots);
197 __ CallStub(&stub);
198 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000199 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000200 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000201 RecordSafepoint(Safepoint::kNoLazyDeopt);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000202 // Context is returned in both rax and rsi. It replaces the context
203 // passed to us. It's saved in the stack and kept live in rsi.
204 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
205
206 // Copy any necessary parameters into the context.
207 int num_parameters = scope()->num_parameters();
208 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000209 Variable* var = scope()->parameter(i);
210 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000211 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
212 (num_parameters - 1 - i) * kPointerSize;
213 // Load parameter from stack.
214 __ movq(rax, Operand(rbp, parameter_offset));
215 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000216 int context_offset = Context::SlotOffset(var->index());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000217 __ movq(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000218 // Update the write barrier. This clobbers rax and rbx.
219 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000220 }
221 }
222 Comment(";;; End allocate local context");
223 }
224
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000225 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000226 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000227 __ CallRuntime(Runtime::kTraceEnter, 0);
228 }
229 return !is_aborted();
230}
231
232
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000233void LCodeGen::GenerateOsrPrologue() {
234 // Generate the OSR entry prologue at the first unknown OSR value, or if there
235 // are none, at the OSR entrypoint instruction.
236 if (osr_pc_offset_ >= 0) return;
237
238 osr_pc_offset_ = masm()->pc_offset();
239
240 // Adjust the frame size, subsuming the unoptimized frame into the
241 // optimized frame.
242 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
243 ASSERT(slots >= 0);
244 __ subq(rsp, Immediate(slots * kPointerSize));
245}
246
247
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000248bool LCodeGen::GenerateJumpTable() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000249 Label needs_frame;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000250 if (jump_table_.length() > 0) {
251 Comment(";;; -------------------- Jump table --------------------");
252 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000253 for (int i = 0; i < jump_table_.length(); i++) {
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000254 __ bind(&jump_table_[i].label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000255 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000256 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000257 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000258 if (id == Deoptimizer::kNotDeoptimizationEntry) {
259 Comment(";;; jump table entry %d.", i);
260 } else {
261 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
262 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000263 if (jump_table_[i].needs_frame) {
264 __ movq(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
danno@chromium.org169691d2013-07-15 08:01:13 +0000265 if (needs_frame.is_bound()) {
266 __ jmp(&needs_frame);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000267 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000268 __ bind(&needs_frame);
269 __ push(rbp);
270 __ movq(rbp, rsp);
271 __ push(rsi);
272 // This variant of deopt can only be used with stubs. Since we don't
273 // have a function pointer to install in the stack frame that we're
274 // building, install a special marker there instead.
275 ASSERT(info()->IsStub());
276 __ Move(rsi, Smi::FromInt(StackFrame::STUB));
277 __ push(rsi);
278 __ movq(rsi, MemOperand(rsp, kPointerSize));
279 __ call(kScratchRegister);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000280 }
281 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000282 __ call(entry, RelocInfo::RUNTIME_ENTRY);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000283 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000284 }
285 return !is_aborted();
286}
287
288
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000289bool LCodeGen::GenerateDeferredCode() {
290 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000291 if (deferred_.length() > 0) {
292 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
293 LDeferredCode* code = deferred_[i];
danno@chromium.org59400602013-08-13 17:09:37 +0000294
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000295 HValue* value =
296 instructions_->at(code->instruction_index())->hydrogen_value();
297 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000298
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000299 Comment(";;; <@%d,#%d> "
300 "-------------------- Deferred %s --------------------",
301 code->instruction_index(),
302 code->instr()->hydrogen_value()->id(),
303 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000304 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000305 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000306 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000307 ASSERT(!frame_is_built_);
308 ASSERT(info()->IsStub());
309 frame_is_built_ = true;
310 // Build the frame in such a way that esi isn't trashed.
311 __ push(rbp); // Caller's frame pointer.
312 __ push(Operand(rbp, StandardFrameConstants::kContextOffset));
313 __ Push(Smi::FromInt(StackFrame::STUB));
314 __ lea(rbp, Operand(rsp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000315 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000316 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000317 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000318 if (NeedsDeferredFrame()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000319 __ bind(code->done());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000320 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000321 ASSERT(frame_is_built_);
322 frame_is_built_ = false;
323 __ movq(rsp, rbp);
324 __ pop(rbp);
325 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000326 __ jmp(code->exit());
327 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000328 }
329
330 // Deferred code is the last part of the instruction sequence. Mark
331 // the generated code as done unless we bailed out.
332 if (!is_aborted()) status_ = DONE;
333 return !is_aborted();
334}
335
336
337bool LCodeGen::GenerateSafepointTable() {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000338 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000339 safepoints_.Emit(masm(), GetStackSlotCount());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000340 return !is_aborted();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000341}
342
343
344Register LCodeGen::ToRegister(int index) const {
345 return Register::FromAllocationIndex(index);
346}
347
348
349XMMRegister LCodeGen::ToDoubleRegister(int index) const {
350 return XMMRegister::FromAllocationIndex(index);
351}
352
353
354Register LCodeGen::ToRegister(LOperand* op) const {
355 ASSERT(op->IsRegister());
356 return ToRegister(op->index());
357}
358
359
360XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
361 ASSERT(op->IsDoubleRegister());
362 return ToDoubleRegister(op->index());
363}
364
365
366bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
367 return op->IsConstantOperand() &&
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000368 chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000369}
370
371
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000372bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
373 return op->IsConstantOperand() &&
374 chunk_->LookupLiteralRepresentation(op).IsSmi();
375}
376
377
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000378bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
379 return op->IsConstantOperand() &&
380 chunk_->LookupLiteralRepresentation(op).IsTagged();
381}
382
383
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000384int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000385 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000386 return constant->Integer32Value();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000387}
388
389
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000390Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
391 HConstant* constant = chunk_->LookupConstant(op);
392 return Smi::FromInt(constant->Integer32Value());
393}
394
395
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000396double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000397 HConstant* constant = chunk_->LookupConstant(op);
398 ASSERT(constant->HasDoubleValue());
399 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000400}
401
402
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000403ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
404 HConstant* constant = chunk_->LookupConstant(op);
405 ASSERT(constant->HasExternalReferenceValue());
406 return constant->ExternalReferenceValue();
407}
408
409
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000410Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000411 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000412 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000413 return constant->handle(isolate());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000414}
415
416
417Operand LCodeGen::ToOperand(LOperand* op) const {
418 // Does not handle registers. In X64 assembler, plain registers are not
419 // representable as an Operand.
420 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000421 return Operand(rbp, StackSlotOffset(op->index()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000422}
423
424
425void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000426 Translation* translation) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000427 if (environment == NULL) return;
428
429 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000430 int translation_size = environment->translation_size();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000431 // The output frame height does not include the parameters.
432 int height = translation_size - environment->parameter_count();
433
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000434 WriteTranslation(environment->outer(), translation);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000435 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000436 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000437 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000438 ? DefineDeoptimizationLiteral(environment->closure())
439 : Translation::kSelfLiteralId;
440
ulan@chromium.org967e2702012-02-28 09:49:15 +0000441 switch (environment->frame_type()) {
442 case JS_FUNCTION:
443 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
444 break;
445 case JS_CONSTRUCT:
446 translation->BeginConstructStubFrame(closure_id, translation_size);
447 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000448 case JS_GETTER:
449 ASSERT(translation_size == 1);
450 ASSERT(height == 0);
451 translation->BeginGetterStubFrame(closure_id);
452 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000453 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000454 ASSERT(translation_size == 2);
455 ASSERT(height == 0);
456 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000457 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000458 case ARGUMENTS_ADAPTOR:
459 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
460 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000461 case STUB:
462 translation->BeginCompiledStubFrame();
463 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000464 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000465
danno@chromium.org59400602013-08-13 17:09:37 +0000466 int object_index = 0;
467 int dematerialized_index = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000468 for (int i = 0; i < translation_size; ++i) {
469 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000470 AddToTranslation(environment,
471 translation,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000472 value,
473 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000474 environment->HasUint32ValueAt(i),
475 &object_index,
476 &dematerialized_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000477 }
478}
479
480
danno@chromium.org59400602013-08-13 17:09:37 +0000481void LCodeGen::AddToTranslation(LEnvironment* environment,
482 Translation* translation,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000483 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000484 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000485 bool is_uint32,
486 int* object_index_pointer,
487 int* dematerialized_index_pointer) {
488 if (op == LEnvironment::materialization_marker()) {
489 int object_index = (*object_index_pointer)++;
490 if (environment->ObjectIsDuplicateAt(object_index)) {
491 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
492 translation->DuplicateObject(dupe_of);
493 return;
494 }
495 int object_length = environment->ObjectLengthAt(object_index);
496 if (environment->ObjectIsArgumentsAt(object_index)) {
497 translation->BeginArgumentsObject(object_length);
498 } else {
499 translation->BeginCapturedObject(object_length);
500 }
501 int dematerialized_index = *dematerialized_index_pointer;
502 int env_offset = environment->translation_size() + dematerialized_index;
503 *dematerialized_index_pointer += object_length;
504 for (int i = 0; i < object_length; ++i) {
505 LOperand* value = environment->values()->at(env_offset + i);
506 AddToTranslation(environment,
507 translation,
508 value,
509 environment->HasTaggedValueAt(env_offset + i),
510 environment->HasUint32ValueAt(env_offset + i),
511 object_index_pointer,
512 dematerialized_index_pointer);
513 }
514 return;
515 }
516
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000517 if (op->IsStackSlot()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000518 if (is_tagged) {
519 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000520 } else if (is_uint32) {
521 translation->StoreUint32StackSlot(op->index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000522 } else {
523 translation->StoreInt32StackSlot(op->index());
524 }
525 } else if (op->IsDoubleStackSlot()) {
526 translation->StoreDoubleStackSlot(op->index());
527 } else if (op->IsArgument()) {
528 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000529 int src_index = GetStackSlotCount() + op->index();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000530 translation->StoreStackSlot(src_index);
531 } else if (op->IsRegister()) {
532 Register reg = ToRegister(op);
533 if (is_tagged) {
534 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000535 } else if (is_uint32) {
536 translation->StoreUint32Register(reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000537 } else {
538 translation->StoreInt32Register(reg);
539 }
540 } else if (op->IsDoubleRegister()) {
541 XMMRegister reg = ToDoubleRegister(op);
542 translation->StoreDoubleRegister(reg);
543 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000544 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000545 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000546 translation->StoreLiteral(src_index);
547 } else {
548 UNREACHABLE();
549 }
550}
551
552
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000553void LCodeGen::CallCodeGeneric(Handle<Code> code,
554 RelocInfo::Mode mode,
555 LInstruction* instr,
556 SafepointMode safepoint_mode,
557 int argc) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000558 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code));
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000559 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000560 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000561 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000562
563 // Signal that we don't inline smi code before these stubs in the
564 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000565 if (code->kind() == Code::BINARY_OP_IC ||
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000566 code->kind() == Code::COMPARE_IC) {
567 __ nop();
568 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000569}
570
571
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000572void LCodeGen::CallCode(Handle<Code> code,
573 RelocInfo::Mode mode,
574 LInstruction* instr) {
575 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0);
576}
577
578
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579void LCodeGen::CallRuntime(const Runtime::Function* function,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000580 int num_arguments,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000581 LInstruction* instr,
582 SaveFPRegsMode save_doubles) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000583 ASSERT(instr != NULL);
584 ASSERT(instr->HasPointerMap());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000585
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000586 __ CallRuntime(function, num_arguments, save_doubles);
587
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000588 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000589}
590
591
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000592void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
593 int argc,
594 LInstruction* instr) {
595 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
596 __ CallRuntimeSaveDoubles(id);
597 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000598 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000599}
600
601
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000602void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
603 Safepoint::DeoptMode mode) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000604 if (!environment->HasBeenRegistered()) {
605 // Physical stack frame layout:
606 // -x ............. -4 0 ..................................... y
607 // [incoming arguments] [spill slots] [pushed outgoing arguments]
608
609 // Layout of the environment:
610 // 0 ..................................................... size-1
611 // [parameters] [locals] [expression stack including arguments]
612
613 // Layout of the translation:
614 // 0 ........................................................ size - 1 + 4
615 // [expression stack including arguments] [locals] [4 words] [parameters]
616 // |>------------ translation_size ------------<|
617
618 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000619 int jsframe_count = 0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000620 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
621 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000622 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000623 ++jsframe_count;
624 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000625 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000626 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000627 WriteTranslation(environment, &translation);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000628 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000629 int pc_offset = masm()->pc_offset();
630 environment->Register(deoptimization_index,
631 translation.index(),
632 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000633 deoptimizations_.Add(environment, environment->zone());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000634 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000635}
636
637
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000638void LCodeGen::DeoptimizeIf(Condition cc,
639 LEnvironment* environment,
640 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000641 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000642 ASSERT(environment->HasBeenRegistered());
643 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000644 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000645 Address entry =
646 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000647 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +0000648 Abort(kBailoutWasNotPrepared);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000649 return;
650 }
651
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000652 ASSERT(FLAG_deopt_every_n_times == 0); // Not yet implemented on x64.
653
danno@chromium.org59400602013-08-13 17:09:37 +0000654 if (info()->ShouldTrapOnDeopt()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000655 Label done;
656 if (cc != no_condition) {
657 __ j(NegateCondition(cc), &done, Label::kNear);
658 }
659 __ int3();
660 __ bind(&done);
661 }
662
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000663 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000664 if (cc == no_condition && frame_is_built_) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000665 __ call(entry, RelocInfo::RUNTIME_ENTRY);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000666 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000667 // We often have several deopts to the same entry, reuse the last
668 // jump entry if this is the case.
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000669 if (jump_table_.is_empty() ||
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000670 jump_table_.last().address != entry ||
671 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000672 jump_table_.last().bailout_type != bailout_type) {
673 Deoptimizer::JumpTableEntry table_entry(entry,
674 bailout_type,
675 !frame_is_built_);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000676 jump_table_.Add(table_entry, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000677 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000678 if (cc == no_condition) {
679 __ jmp(&jump_table_.last().label);
680 } else {
681 __ j(cc, &jump_table_.last().label);
682 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000683 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000684}
685
686
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000687void LCodeGen::DeoptimizeIf(Condition cc,
688 LEnvironment* environment) {
689 Deoptimizer::BailoutType bailout_type = info()->IsStub()
690 ? Deoptimizer::LAZY
691 : Deoptimizer::EAGER;
692 DeoptimizeIf(cc, environment, bailout_type);
693}
694
695
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000696void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
697 ZoneList<Handle<Map> > maps(1, zone());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000698 ZoneList<Handle<JSObject> > objects(1, zone());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000699 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
700 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000701 if (Code::IsWeakEmbeddedObject(code->kind(), it.rinfo()->target_object())) {
702 if (it.rinfo()->target_object()->IsMap()) {
703 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000704 maps.Add(map, zone());
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000705 } else if (it.rinfo()->target_object()->IsJSObject()) {
706 Handle<JSObject> object(JSObject::cast(it.rinfo()->target_object()));
707 objects.Add(object, zone());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000708 }
709 }
710 }
711#ifdef VERIFY_HEAP
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000712 // This disables verification of weak embedded objects after full GC.
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000713 // AddDependentCode can cause a GC, which would observe the state where
714 // this code is not yet in the depended code lists of the embedded maps.
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000715 NoWeakObjectVerificationScope disable_verification_of_embedded_objects;
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000716#endif
717 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000718 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000719 }
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +0000720 for (int i = 0; i < objects.length(); i++) {
721 AddWeakObjectToCodeDependency(isolate()->heap(), objects.at(i), code);
722 }
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000723}
724
725
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000726void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
727 int length = deoptimizations_.length();
728 if (length == 0) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000729 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000730 factory()->NewDeoptimizationInputData(length, TENURED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000731
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000732 Handle<ByteArray> translations =
733 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000734 data->SetTranslationByteArray(*translations);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000735 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
736
737 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000738 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000739 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000740 for (int i = 0; i < deoptimization_literals_.length(); i++) {
741 literals->set(i, *deoptimization_literals_[i]);
742 }
743 data->SetLiteralArray(*literals);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000744 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000745
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000746 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000747 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
748
749 // Populate the deoptimization entries.
750 for (int i = 0; i < length; i++) {
751 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000752 data->SetAstId(i, env->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000753 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
754 data->SetArgumentsStackHeight(i,
755 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000756 data->SetPc(i, Smi::FromInt(env->pc_offset()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000757 }
758 code->set_deoptimization_data(*data);
759}
760
761
762int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
763 int result = deoptimization_literals_.length();
764 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
765 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
766 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000767 deoptimization_literals_.Add(literal, zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000768 return result;
769}
770
771
772void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
773 ASSERT(deoptimization_literals_.length() == 0);
774
775 const ZoneList<Handle<JSFunction> >* inlined_closures =
776 chunk()->inlined_closures();
777
778 for (int i = 0, length = inlined_closures->length();
779 i < length;
780 i++) {
781 DefineDeoptimizationLiteral(inlined_closures->at(i));
782 }
783
784 inlined_function_count_ = deoptimization_literals_.length();
785}
786
787
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000788void LCodeGen::RecordSafepointWithLazyDeopt(
789 LInstruction* instr, SafepointMode safepoint_mode, int argc) {
790 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
791 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
792 } else {
793 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
794 RecordSafepointWithRegisters(
795 instr->pointer_map(), argc, Safepoint::kLazyDeopt);
796 }
797}
798
799
ager@chromium.org378b34e2011-01-28 08:04:38 +0000800void LCodeGen::RecordSafepoint(
801 LPointerMap* pointers,
802 Safepoint::Kind kind,
803 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000804 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000805 ASSERT(kind == expected_safepoint_kind_);
806
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000807 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000808
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000809 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000810 kind, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000811 for (int i = 0; i < operands->length(); i++) {
812 LOperand* pointer = operands->at(i);
813 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000814 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000815 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000816 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000817 }
818 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000819 if (kind & Safepoint::kWithRegisters) {
820 // Register rsi always contains a pointer to the context.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000821 safepoint.DefinePointerRegister(rsi, zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000822 }
823}
824
825
826void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000827 Safepoint::DeoptMode deopt_mode) {
828 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000829}
830
831
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000832void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000833 LPointerMap empty_pointers(zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000834 RecordSafepoint(&empty_pointers, deopt_mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000835}
836
837
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000838void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
839 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000840 Safepoint::DeoptMode deopt_mode) {
841 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000842}
843
844
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000845void LCodeGen::RecordAndWritePosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000846 if (position == RelocInfo::kNoPosition) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000847 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000848 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +0000849}
850
851
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000852static const char* LabelType(LLabel* label) {
853 if (label->is_loop_header()) return " (loop header)";
854 if (label->is_osr_entry()) return " (OSR entry)";
855 return "";
856}
857
858
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000859void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000860 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
861 current_instruction_,
862 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000863 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000864 LabelType(label));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000865 __ bind(label->label());
866 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000867 DoGap(label);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000868}
869
870
871void LCodeGen::DoParallelMove(LParallelMove* move) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000872 resolver_.Resolve(move);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000873}
874
875
876void LCodeGen::DoGap(LGap* gap) {
877 for (int i = LGap::FIRST_INNER_POSITION;
878 i <= LGap::LAST_INNER_POSITION;
879 i++) {
880 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
881 LParallelMove* move = gap->GetParallelMove(inner_pos);
882 if (move != NULL) DoParallelMove(move);
883 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000884}
885
886
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000887void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
888 DoGap(instr);
889}
890
891
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000892void LCodeGen::DoParameter(LParameter* instr) {
893 // Nothing to do.
894}
895
896
897void LCodeGen::DoCallStub(LCallStub* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000898 ASSERT(ToRegister(instr->result()).is(rax));
899 switch (instr->hydrogen()->major_key()) {
900 case CodeStub::RegExpConstructResult: {
901 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000902 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000903 break;
904 }
905 case CodeStub::RegExpExec: {
906 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000907 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000908 break;
909 }
910 case CodeStub::SubString: {
911 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000912 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000913 break;
914 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000915 case CodeStub::StringCompare: {
916 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000917 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000918 break;
919 }
920 case CodeStub::TranscendentalCache: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000921 TranscendentalCacheStub stub(instr->transcendental_type(),
922 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000923 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000924 break;
925 }
926 default:
927 UNREACHABLE();
928 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000929}
930
931
932void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000933 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000934}
935
936
937void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000938 HMod* hmod = instr->hydrogen();
939 HValue* left = hmod->left();
940 HValue* right = hmod->right();
941 if (hmod->HasPowerOf2Divisor()) {
942 // TODO(svenpanne) We should really do the strength reduction on the
943 // Hydrogen level.
944 Register left_reg = ToRegister(instr->left());
945 ASSERT(left_reg.is(ToRegister(instr->result())));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000946
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000947 // Note: The code below even works when right contains kMinInt.
948 int32_t divisor = Abs(right->GetInteger32Constant());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000949
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000950 Label left_is_not_negative, done;
951 if (left->CanBeNegative()) {
952 __ testl(left_reg, left_reg);
953 __ j(not_sign, &left_is_not_negative, Label::kNear);
954 __ negl(left_reg);
955 __ andl(left_reg, Immediate(divisor - 1));
956 __ negl(left_reg);
957 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
958 DeoptimizeIf(zero, instr->environment());
959 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000960 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000961 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000962
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000963 __ bind(&left_is_not_negative);
964 __ andl(left_reg, Immediate(divisor - 1));
965 __ bind(&done);
966
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000967 } else if (hmod->fixed_right_arg().has_value) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000968 Register left_reg = ToRegister(instr->left());
969 ASSERT(left_reg.is(ToRegister(instr->result())));
970 Register right_reg = ToRegister(instr->right());
971
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000972 int32_t divisor = hmod->fixed_right_arg().value;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000973 ASSERT(IsPowerOf2(divisor));
974
975 // Check if our assumption of a fixed right operand still holds.
976 __ cmpl(right_reg, Immediate(divisor));
977 DeoptimizeIf(not_equal, instr->environment());
978
979 Label left_is_not_negative, done;
980 if (left->CanBeNegative()) {
981 __ testl(left_reg, left_reg);
982 __ j(not_sign, &left_is_not_negative, Label::kNear);
983 __ negl(left_reg);
984 __ andl(left_reg, Immediate(divisor - 1));
985 __ negl(left_reg);
986 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
987 DeoptimizeIf(zero, instr->environment());
988 }
989 __ jmp(&done, Label::kNear);
990 }
991
992 __ bind(&left_is_not_negative);
993 __ andl(left_reg, Immediate(divisor - 1));
994 __ bind(&done);
995
996 } else {
997 Register left_reg = ToRegister(instr->left());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000998 ASSERT(left_reg.is(rax));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000999 Register right_reg = ToRegister(instr->right());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001000 ASSERT(!right_reg.is(rax));
1001 ASSERT(!right_reg.is(rdx));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001002 Register result_reg = ToRegister(instr->result());
1003 ASSERT(result_reg.is(rdx));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001004
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001005 Label done;
1006 // Check for x % 0, idiv would signal a divide error. We have to
1007 // deopt in this case because we can't return a NaN.
1008 if (right->CanBeZero()) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001009 __ testl(right_reg, right_reg);
1010 DeoptimizeIf(zero, instr->environment());
1011 }
1012
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001013 // Check for kMinInt % -1, idiv would signal a divide error. We
1014 // have to deopt if we care about -0, because we can't return that.
1015 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1016 Label no_overflow_possible;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001017 __ cmpl(left_reg, Immediate(kMinInt));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001018 __ j(not_zero, &no_overflow_possible, Label::kNear);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001019 __ cmpl(right_reg, Immediate(-1));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001020 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1021 DeoptimizeIf(equal, instr->environment());
1022 } else {
1023 __ j(not_equal, &no_overflow_possible, Label::kNear);
1024 __ Set(result_reg, 0);
1025 __ jmp(&done, Label::kNear);
1026 }
1027 __ bind(&no_overflow_possible);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001028 }
1029
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001030 // Sign extend dividend in eax into edx:eax, since we are using only the low
1031 // 32 bits of the values.
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001032 __ cdq();
1033
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001034 // If we care about -0, test if the dividend is <0 and the result is 0.
1035 if (left->CanBeNegative() &&
1036 hmod->CanBeZero() &&
1037 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001038 Label positive_left;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001039 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001040 __ j(not_sign, &positive_left, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001041 __ idivl(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001042 __ testl(result_reg, result_reg);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001043 DeoptimizeIf(zero, instr->environment());
1044 __ jmp(&done, Label::kNear);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001045 __ bind(&positive_left);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001046 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001047 __ idivl(right_reg);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001048 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001049 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001050}
1051
1052
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001053void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001054 ASSERT(instr->right()->IsConstantOperand());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001055
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001056 const Register dividend = ToRegister(instr->left());
1057 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001058 const Register result = ToRegister(instr->result());
1059
1060 switch (divisor) {
1061 case 0:
1062 DeoptimizeIf(no_condition, instr->environment());
1063 return;
1064
1065 case 1:
1066 if (!result.is(dividend)) {
1067 __ movl(result, dividend);
1068 }
1069 return;
1070
1071 case -1:
1072 if (!result.is(dividend)) {
1073 __ movl(result, dividend);
1074 }
1075 __ negl(result);
1076 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1077 DeoptimizeIf(zero, instr->environment());
1078 }
1079 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1080 DeoptimizeIf(overflow, instr->environment());
1081 }
1082 return;
1083 }
1084
1085 uint32_t divisor_abs = abs(divisor);
1086 if (IsPowerOf2(divisor_abs)) {
1087 int32_t power = WhichPowerOf2(divisor_abs);
1088 if (divisor < 0) {
1089 __ movsxlq(result, dividend);
1090 __ neg(result);
1091 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1092 DeoptimizeIf(zero, instr->environment());
1093 }
1094 __ sar(result, Immediate(power));
1095 } else {
1096 if (!result.is(dividend)) {
1097 __ movl(result, dividend);
1098 }
1099 __ sarl(result, Immediate(power));
1100 }
1101 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001102 Register reg1 = ToRegister(instr->temp());
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001103 Register reg2 = ToRegister(instr->result());
1104
1105 // Find b which: 2^b < divisor_abs < 2^(b+1).
1106 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1107 unsigned shift = 32 + b; // Precision +1bit (effectively).
1108 double multiplier_f =
1109 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1110 int64_t multiplier;
1111 if (multiplier_f - floor(multiplier_f) < 0.5) {
1112 multiplier = static_cast<int64_t>(floor(multiplier_f));
1113 } else {
1114 multiplier = static_cast<int64_t>(floor(multiplier_f)) + 1;
1115 }
1116 // The multiplier is a uint32.
1117 ASSERT(multiplier > 0 &&
1118 multiplier < (static_cast<int64_t>(1) << 32));
1119 // The multiply is int64, so sign-extend to r64.
1120 __ movsxlq(reg1, dividend);
1121 if (divisor < 0 &&
1122 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1123 __ neg(reg1);
1124 DeoptimizeIf(zero, instr->environment());
1125 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001126 __ movq(reg2, multiplier, RelocInfo::NONE64);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001127 // Result just fit in r64, because it's int32 * uint32.
1128 __ imul(reg2, reg1);
1129
1130 __ addq(reg2, Immediate(1 << 30));
1131 __ sar(reg2, Immediate(shift));
1132 }
1133}
1134
1135
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001136void LCodeGen::DoDivI(LDivI* instr) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001137 if (!instr->is_flooring() && instr->hydrogen()->HasPowerOf2Divisor()) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001138 Register dividend = ToRegister(instr->left());
1139 int32_t divisor =
1140 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
1141 int32_t test_value = 0;
1142 int32_t power = 0;
1143
1144 if (divisor > 0) {
1145 test_value = divisor - 1;
1146 power = WhichPowerOf2(divisor);
1147 } else {
1148 // Check for (0 / -x) that will produce negative zero.
1149 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1150 __ testl(dividend, dividend);
1151 DeoptimizeIf(zero, instr->environment());
1152 }
1153 // Check for (kMinInt / -1).
1154 if (divisor == -1 && instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1155 __ cmpl(dividend, Immediate(kMinInt));
1156 DeoptimizeIf(zero, instr->environment());
1157 }
1158 test_value = - divisor - 1;
1159 power = WhichPowerOf2(-divisor);
1160 }
1161
1162 if (test_value != 0) {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001163 if (instr->hydrogen()->CheckFlag(
1164 HInstruction::kAllUsesTruncatingToInt32)) {
1165 Label done, negative;
1166 __ cmpl(dividend, Immediate(0));
1167 __ j(less, &negative, Label::kNear);
1168 __ sarl(dividend, Immediate(power));
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001169 if (divisor < 0) __ negl(dividend);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001170 __ jmp(&done, Label::kNear);
1171
1172 __ bind(&negative);
1173 __ negl(dividend);
1174 __ sarl(dividend, Immediate(power));
1175 if (divisor > 0) __ negl(dividend);
1176 __ bind(&done);
1177 return; // Don't fall through to "__ neg" below.
1178 } else {
1179 // Deoptimize if remainder is not 0.
1180 __ testl(dividend, Immediate(test_value));
1181 DeoptimizeIf(not_zero, instr->environment());
1182 __ sarl(dividend, Immediate(power));
1183 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001184 }
1185
1186 if (divisor < 0) __ negl(dividend);
1187
1188 return;
1189 }
1190
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001191 LOperand* right = instr->right();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001192 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001193 ASSERT(ToRegister(instr->left()).is(rax));
1194 ASSERT(!ToRegister(instr->right()).is(rax));
1195 ASSERT(!ToRegister(instr->right()).is(rdx));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001196
1197 Register left_reg = rax;
1198
1199 // Check for x / 0.
1200 Register right_reg = ToRegister(right);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001201 if (instr->hydrogen_value()->CheckFlag(HValue::kCanBeDivByZero)) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001202 __ testl(right_reg, right_reg);
1203 DeoptimizeIf(zero, instr->environment());
1204 }
1205
1206 // Check for (0 / -x) that will produce negative zero.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001207 if (instr->hydrogen_value()->CheckFlag(HValue::kBailoutOnMinusZero)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001208 Label left_not_zero;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001209 __ testl(left_reg, left_reg);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001210 __ j(not_zero, &left_not_zero, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001211 __ testl(right_reg, right_reg);
1212 DeoptimizeIf(sign, instr->environment());
1213 __ bind(&left_not_zero);
1214 }
1215
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001216 // Check for (kMinInt / -1).
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001217 if (instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001218 Label left_not_min_int;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001219 __ cmpl(left_reg, Immediate(kMinInt));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001220 __ j(not_zero, &left_not_min_int, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001221 __ cmpl(right_reg, Immediate(-1));
1222 DeoptimizeIf(zero, instr->environment());
1223 __ bind(&left_not_min_int);
1224 }
1225
1226 // Sign extend to rdx.
1227 __ cdq();
1228 __ idivl(right_reg);
1229
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001230 if (instr->is_flooring()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001231 Label done;
1232 __ testl(rdx, rdx);
1233 __ j(zero, &done, Label::kNear);
1234 __ xorl(rdx, right_reg);
1235 __ sarl(rdx, Immediate(31));
1236 __ addl(rax, rdx);
1237 __ bind(&done);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001238 } else if (!instr->hydrogen()->CheckFlag(
1239 HInstruction::kAllUsesTruncatingToInt32)) {
1240 // Deoptimize if remainder is not 0.
1241 __ testl(rdx, rdx);
1242 DeoptimizeIf(not_zero, instr->environment());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001243 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001244}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001245
1246
1247void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001248 Register left = ToRegister(instr->left());
1249 LOperand* right = instr->right();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001250
1251 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001252 if (instr->hydrogen_value()->representation().IsSmi()) {
1253 __ movq(kScratchRegister, left);
1254 } else {
1255 __ movl(kScratchRegister, left);
1256 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001257 }
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259 bool can_overflow =
1260 instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001261 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001262 int32_t right_value = ToInteger32(LConstantOperand::cast(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001263 if (right_value == -1) {
1264 __ negl(left);
1265 } else if (right_value == 0) {
1266 __ xorl(left, left);
1267 } else if (right_value == 2) {
1268 __ addl(left, left);
1269 } else if (!can_overflow) {
1270 // If the multiplication is known to not overflow, we
1271 // can use operations that don't set the overflow flag
1272 // correctly.
1273 switch (right_value) {
1274 case 1:
1275 // Do nothing.
1276 break;
1277 case 3:
1278 __ leal(left, Operand(left, left, times_2, 0));
1279 break;
1280 case 4:
1281 __ shll(left, Immediate(2));
1282 break;
1283 case 5:
1284 __ leal(left, Operand(left, left, times_4, 0));
1285 break;
1286 case 8:
1287 __ shll(left, Immediate(3));
1288 break;
1289 case 9:
1290 __ leal(left, Operand(left, left, times_8, 0));
1291 break;
1292 case 16:
1293 __ shll(left, Immediate(4));
1294 break;
1295 default:
1296 __ imull(left, left, Immediate(right_value));
1297 break;
1298 }
1299 } else {
1300 __ imull(left, left, Immediate(right_value));
1301 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001302 } else if (right->IsStackSlot()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001303 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001304 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001305 __ imul(left, ToOperand(right));
1306 } else {
1307 __ imull(left, ToOperand(right));
1308 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001309 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001310 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001311 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001312 __ imul(left, ToRegister(right));
1313 } else {
1314 __ imull(left, ToRegister(right));
1315 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001316 }
1317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 if (can_overflow) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001319 DeoptimizeIf(overflow, instr->environment());
1320 }
1321
1322 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1323 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001324 Label done;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001325 if (instr->hydrogen_value()->representation().IsSmi()) {
1326 __ testq(left, left);
1327 } else {
1328 __ testl(left, left);
1329 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001330 __ j(not_zero, &done, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001331 if (right->IsConstantOperand()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001332 // Constant can't be represented as Smi due to immediate size limit.
1333 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001334 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001335 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001336 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1337 __ cmpl(kScratchRegister, Immediate(0));
1338 DeoptimizeIf(less, instr->environment());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001339 }
1340 } else if (right->IsStackSlot()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001341 if (instr->hydrogen_value()->representation().IsSmi()) {
1342 __ or_(kScratchRegister, ToOperand(right));
1343 } else {
1344 __ orl(kScratchRegister, ToOperand(right));
1345 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001346 DeoptimizeIf(sign, instr->environment());
1347 } else {
1348 // Test the non-zero operand for negative sign.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001349 if (instr->hydrogen_value()->representation().IsSmi()) {
1350 __ or_(kScratchRegister, ToRegister(right));
1351 } else {
1352 __ orl(kScratchRegister, ToRegister(right));
1353 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001354 DeoptimizeIf(sign, instr->environment());
1355 }
1356 __ bind(&done);
1357 }
1358}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001359
1360
1361void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001362 LOperand* left = instr->left();
1363 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001364 ASSERT(left->Equals(instr->result()));
1365 ASSERT(left->IsRegister());
1366
1367 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001368 int32_t right_operand = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001369 switch (instr->op()) {
1370 case Token::BIT_AND:
1371 __ andl(ToRegister(left), Immediate(right_operand));
1372 break;
1373 case Token::BIT_OR:
1374 __ orl(ToRegister(left), Immediate(right_operand));
1375 break;
1376 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001377 if (right_operand == int32_t(~0)) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001378 __ notl(ToRegister(left));
danno@chromium.org59400602013-08-13 17:09:37 +00001379 } else {
1380 __ xorl(ToRegister(left), Immediate(right_operand));
1381 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001382 break;
1383 default:
1384 UNREACHABLE();
1385 break;
1386 }
1387 } else if (right->IsStackSlot()) {
1388 switch (instr->op()) {
1389 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001390 __ and_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001391 break;
1392 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001393 __ or_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001394 break;
1395 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001396 __ xor_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001397 break;
1398 default:
1399 UNREACHABLE();
1400 break;
1401 }
1402 } else {
1403 ASSERT(right->IsRegister());
1404 switch (instr->op()) {
1405 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001406 __ and_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001407 break;
1408 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001409 __ or_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001410 break;
1411 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001412 __ xor_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001413 break;
1414 default:
1415 UNREACHABLE();
1416 break;
1417 }
1418 }
1419}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001420
1421
1422void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001423 LOperand* left = instr->left();
1424 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001425 ASSERT(left->Equals(instr->result()));
1426 ASSERT(left->IsRegister());
1427 if (right->IsRegister()) {
1428 ASSERT(ToRegister(right).is(rcx));
1429
1430 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001431 case Token::ROR:
1432 __ rorl_cl(ToRegister(left));
1433 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001434 case Token::SAR:
1435 __ sarl_cl(ToRegister(left));
1436 break;
1437 case Token::SHR:
1438 __ shrl_cl(ToRegister(left));
1439 if (instr->can_deopt()) {
1440 __ testl(ToRegister(left), ToRegister(left));
1441 DeoptimizeIf(negative, instr->environment());
1442 }
1443 break;
1444 case Token::SHL:
1445 __ shll_cl(ToRegister(left));
1446 break;
1447 default:
1448 UNREACHABLE();
1449 break;
1450 }
1451 } else {
danno@chromium.org59400602013-08-13 17:09:37 +00001452 int32_t value = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001453 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1454 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001455 case Token::ROR:
1456 if (shift_count != 0) {
1457 __ rorl(ToRegister(left), Immediate(shift_count));
1458 }
1459 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001460 case Token::SAR:
1461 if (shift_count != 0) {
1462 __ sarl(ToRegister(left), Immediate(shift_count));
1463 }
1464 break;
1465 case Token::SHR:
1466 if (shift_count == 0 && instr->can_deopt()) {
1467 __ testl(ToRegister(left), ToRegister(left));
1468 DeoptimizeIf(negative, instr->environment());
1469 } else {
1470 __ shrl(ToRegister(left), Immediate(shift_count));
1471 }
1472 break;
1473 case Token::SHL:
1474 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001475 if (instr->hydrogen_value()->representation().IsSmi()) {
1476 __ shl(ToRegister(left), Immediate(shift_count));
1477 } else {
1478 __ shll(ToRegister(left), Immediate(shift_count));
1479 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001480 }
1481 break;
1482 default:
1483 UNREACHABLE();
1484 break;
1485 }
1486 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001487}
1488
1489
1490void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001491 LOperand* left = instr->left();
1492 LOperand* right = instr->right();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001493 ASSERT(left->Equals(instr->result()));
1494
1495 if (right->IsConstantOperand()) {
1496 __ subl(ToRegister(left),
1497 Immediate(ToInteger32(LConstantOperand::cast(right))));
1498 } else if (right->IsRegister()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001499 if (instr->hydrogen_value()->representation().IsSmi()) {
1500 __ subq(ToRegister(left), ToRegister(right));
1501 } else {
1502 __ subl(ToRegister(left), ToRegister(right));
1503 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001504 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001505 if (instr->hydrogen_value()->representation().IsSmi()) {
1506 __ subq(ToRegister(left), ToOperand(right));
1507 } else {
1508 __ subl(ToRegister(left), ToOperand(right));
1509 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001510 }
1511
1512 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1513 DeoptimizeIf(overflow, instr->environment());
1514 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001515}
1516
1517
1518void LCodeGen::DoConstantI(LConstantI* instr) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001519 __ Set(ToRegister(instr->result()), instr->value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001520}
1521
1522
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001523void LCodeGen::DoConstantS(LConstantS* instr) {
1524 __ Move(ToRegister(instr->result()), instr->value());
1525}
1526
1527
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001528void LCodeGen::DoConstantD(LConstantD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001529 ASSERT(instr->result()->IsDoubleRegister());
1530 XMMRegister res = ToDoubleRegister(instr->result());
1531 double v = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001532 uint64_t int_val = BitCast<uint64_t, double>(v);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001533 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1534 // do so if the constant is -0.0.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001535 if (int_val == 0) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001536 __ xorps(res, res);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001537 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001538 Register tmp = ToRegister(instr->temp());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001539 __ Set(tmp, int_val);
1540 __ movq(res, tmp);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001541 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001542}
1543
1544
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001545void LCodeGen::DoConstantE(LConstantE* instr) {
1546 __ LoadAddress(ToRegister(instr->result()), instr->value());
1547}
1548
1549
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001550void LCodeGen::DoConstantT(LConstantT* instr) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001551 Handle<Object> value = instr->value(isolate());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001552 __ Move(ToRegister(instr->result()), value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001553}
1554
1555
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001556void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1557 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001558 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001559 __ EnumLength(result, map);
1560}
1561
1562
whesse@chromium.org7b260152011-06-20 15:33:18 +00001563void LCodeGen::DoElementsKind(LElementsKind* instr) {
1564 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001565 Register input = ToRegister(instr->value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001566
1567 // Load map into |result|.
1568 __ movq(result, FieldOperand(input, HeapObject::kMapOffset));
1569 // Load the map's "bit field 2" into |result|. We only need the first byte.
1570 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset));
1571 // Retrieve elements_kind from bit field 2.
1572 __ and_(result, Immediate(Map::kElementsKindMask));
1573 __ shr(result, Immediate(Map::kElementsKindShift));
1574}
1575
1576
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001577void LCodeGen::DoValueOf(LValueOf* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001578 Register input = ToRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001579 Register result = ToRegister(instr->result());
1580 ASSERT(input.is(result));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001581 Label done;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001582
1583 if (!instr->hydrogen()->value()->IsHeapObject()) {
1584 // If the object is a smi return the object.
1585 __ JumpIfSmi(input, &done, Label::kNear);
1586 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001587
1588 // If the object is not a value type, return the object.
1589 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001590 __ j(not_equal, &done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001591 __ movq(result, FieldOperand(input, JSValue::kValueOffset));
1592
1593 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001594}
1595
1596
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001597void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001598 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001599 Register result = ToRegister(instr->result());
1600 Smi* index = instr->index();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001601 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001602 ASSERT(object.is(result));
1603 ASSERT(object.is(rax));
1604
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001605 Condition cc = masm()->CheckSmi(object);
1606 DeoptimizeIf(cc, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001607 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001608 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001609
1610 if (index->value() == 0) {
1611 __ movq(result, FieldOperand(object, JSDate::kValueOffset));
1612 } else {
1613 if (index->value() < JSDate::kFirstUncachedField) {
1614 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001615 Operand stamp_operand = __ ExternalOperand(stamp);
1616 __ movq(kScratchRegister, stamp_operand);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001617 __ cmpq(kScratchRegister, FieldOperand(object,
1618 JSDate::kCacheStampOffset));
1619 __ j(not_equal, &runtime, Label::kNear);
1620 __ movq(result, FieldOperand(object, JSDate::kValueOffset +
1621 kPointerSize * index->value()));
1622 __ jmp(&done);
1623 }
1624 __ bind(&runtime);
1625 __ PrepareCallCFunction(2);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001626 __ movq(arg_reg_1, object);
1627 __ movq(arg_reg_2, index, RelocInfo::NONE64);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001628 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1629 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
1630 __ bind(&done);
1631 }
1632}
1633
1634
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001635void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001636 Register string = ToRegister(instr->string());
1637 Register index = ToRegister(instr->index());
1638 Register value = ToRegister(instr->value());
1639 String::Encoding encoding = instr->encoding();
1640
1641 if (FLAG_debug_code) {
1642 __ push(value);
1643 __ movq(value, FieldOperand(string, HeapObject::kMapOffset));
1644 __ movzxbq(value, FieldOperand(value, Map::kInstanceTypeOffset));
1645
1646 __ andb(value, Immediate(kStringRepresentationMask | kStringEncodingMask));
1647 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1648 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1649 __ cmpq(value, Immediate(encoding == String::ONE_BYTE_ENCODING
1650 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00001651 __ Check(equal, kUnexpectedStringType);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001652 __ pop(value);
1653 }
1654
1655 if (encoding == String::ONE_BYTE_ENCODING) {
1656 __ movb(FieldOperand(string, index, times_1, SeqString::kHeaderSize),
1657 value);
1658 } else {
1659 __ movw(FieldOperand(string, index, times_2, SeqString::kHeaderSize),
1660 value);
1661 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001662}
1663
1664
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001665void LCodeGen::DoThrow(LThrow* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001666 __ push(ToRegister(instr->value()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001667 CallRuntime(Runtime::kThrow, 1, instr);
1668
1669 if (FLAG_debug_code) {
1670 Comment("Unreachable code.");
1671 __ int3();
1672 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001673}
1674
1675
1676void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001677 LOperand* left = instr->left();
1678 LOperand* right = instr->right();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001679
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001680 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1681 if (right->IsConstantOperand()) {
1682 int32_t offset = ToInteger32(LConstantOperand::cast(right));
jkummerow@chromium.orgfee992b2013-06-19 18:17:45 +00001683 __ leal(ToRegister(instr->result()),
1684 MemOperand(ToRegister(left), offset));
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001685 } else {
1686 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001687 if (instr->hydrogen()->representation().IsSmi()) {
1688 __ lea(ToRegister(instr->result()), address);
1689 } else {
1690 __ leal(ToRegister(instr->result()), address);
1691 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001692 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001693 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001694 if (right->IsConstantOperand()) {
1695 __ addl(ToRegister(left),
1696 Immediate(ToInteger32(LConstantOperand::cast(right))));
1697 } else if (right->IsRegister()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001698 if (instr->hydrogen_value()->representation().IsSmi()) {
1699 __ addq(ToRegister(left), ToRegister(right));
1700 } else {
1701 __ addl(ToRegister(left), ToRegister(right));
1702 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001703 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001704 if (instr->hydrogen_value()->representation().IsSmi()) {
1705 __ addq(ToRegister(left), ToOperand(right));
1706 } else {
1707 __ addl(ToRegister(left), ToOperand(right));
1708 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001709 }
1710 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1711 DeoptimizeIf(overflow, instr->environment());
1712 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001713 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001714}
1715
1716
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001717void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001718 LOperand* left = instr->left();
1719 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001720 ASSERT(left->Equals(instr->result()));
1721 HMathMinMax::Operation operation = instr->hydrogen()->operation();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001722 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001723 Label return_left;
1724 Condition condition = (operation == HMathMinMax::kMathMin)
1725 ? less_equal
1726 : greater_equal;
1727 Register left_reg = ToRegister(left);
1728 if (right->IsConstantOperand()) {
1729 Immediate right_imm =
1730 Immediate(ToInteger32(LConstantOperand::cast(right)));
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001731 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
ulan@chromium.org4121f232012-12-27 15:57:11 +00001732 __ cmpl(left_reg, right_imm);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001733 __ j(condition, &return_left, Label::kNear);
1734 __ movq(left_reg, right_imm);
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001735 } else if (right->IsRegister()) {
1736 Register right_reg = ToRegister(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001737 if (instr->hydrogen_value()->representation().IsSmi()) {
1738 __ cmpq(left_reg, right_reg);
1739 } else {
1740 __ cmpl(left_reg, right_reg);
1741 }
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001742 __ j(condition, &return_left, Label::kNear);
1743 __ movq(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001744 } else {
1745 Operand right_op = ToOperand(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001746 if (instr->hydrogen_value()->representation().IsSmi()) {
1747 __ cmpq(left_reg, right_op);
1748 } else {
1749 __ cmpl(left_reg, right_op);
1750 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001751 __ j(condition, &return_left, Label::kNear);
1752 __ movq(left_reg, right_op);
1753 }
1754 __ bind(&return_left);
1755 } else {
1756 ASSERT(instr->hydrogen()->representation().IsDouble());
1757 Label check_nan_left, check_zero, return_left, return_right;
1758 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1759 XMMRegister left_reg = ToDoubleRegister(left);
1760 XMMRegister right_reg = ToDoubleRegister(right);
1761 __ ucomisd(left_reg, right_reg);
1762 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1763 __ j(equal, &check_zero, Label::kNear); // left == right.
1764 __ j(condition, &return_left, Label::kNear);
1765 __ jmp(&return_right, Label::kNear);
1766
1767 __ bind(&check_zero);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001768 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001769 __ xorps(xmm_scratch, xmm_scratch);
1770 __ ucomisd(left_reg, xmm_scratch);
1771 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1772 // At this point, both left and right are either 0 or -0.
1773 if (operation == HMathMinMax::kMathMin) {
1774 __ orpd(left_reg, right_reg);
1775 } else {
1776 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1777 __ addsd(left_reg, right_reg);
1778 }
1779 __ jmp(&return_left, Label::kNear);
1780
1781 __ bind(&check_nan_left);
1782 __ ucomisd(left_reg, left_reg); // NaN check.
1783 __ j(parity_even, &return_left, Label::kNear);
1784 __ bind(&return_right);
1785 __ movsd(left_reg, right_reg);
1786
1787 __ bind(&return_left);
1788 }
1789}
1790
1791
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001792void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001793 XMMRegister left = ToDoubleRegister(instr->left());
1794 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001795 XMMRegister result = ToDoubleRegister(instr->result());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001796 // All operations except MOD are computed in-place.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001797 ASSERT(instr->op() == Token::MOD || left.is(result));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001798 switch (instr->op()) {
1799 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001800 __ addsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001801 break;
1802 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001803 __ subsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001804 break;
1805 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001806 __ mulsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001807 break;
1808 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001809 __ divsd(left, right);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001810 // Don't delete this mov. It may improve performance on some CPUs,
1811 // when there is a mulsd depending on the result
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001812 __ movaps(left, left);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001813 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001814 case Token::MOD: {
1815 XMMRegister xmm_scratch = double_scratch0();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001816 __ PrepareCallCFunction(2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001817 __ movaps(xmm_scratch, left);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001818 ASSERT(right.is(xmm1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 __ CallCFunction(
1820 ExternalReference::double_fp_operation(Token::MOD, isolate()), 2);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001821 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001822 __ movaps(result, xmm_scratch);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001823 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001824 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001825 default:
1826 UNREACHABLE();
1827 break;
1828 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001829}
1830
1831
1832void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001833 ASSERT(ToRegister(instr->left()).is(rdx));
1834 ASSERT(ToRegister(instr->right()).is(rax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001835 ASSERT(ToRegister(instr->result()).is(rax));
1836
danno@chromium.org40cb8782011-05-25 07:58:50 +00001837 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001838 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001839 __ nop(); // Signals no inlined code.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001840}
1841
1842
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001843template<class InstrType>
1844void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001845 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001846 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001847
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001848 int next_block = GetNextEmittedBlock();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001849
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001850 if (right_block == left_block || cc == no_condition) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001851 EmitGoto(left_block);
1852 } else if (left_block == next_block) {
1853 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1854 } else if (right_block == next_block) {
1855 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1856 } else {
1857 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1858 if (cc != always) {
1859 __ jmp(chunk_->GetAssemblyLabel(right_block));
1860 }
1861 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001862}
1863
1864
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00001865template<class InstrType>
1866void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
1867 int false_block = instr->FalseDestination(chunk_);
1868 __ j(cc, chunk_->GetAssemblyLabel(false_block));
1869}
1870
1871
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001872void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1873 __ int3();
1874}
1875
1876
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001877void LCodeGen::DoBranch(LBranch* instr) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001878 Representation r = instr->hydrogen()->value()->representation();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001879 if (r.IsInteger32()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001880 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001881 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001882 __ testl(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001883 EmitBranch(instr, not_zero);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001884 } else if (r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001885 ASSERT(!info()->IsStub());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001886 Register reg = ToRegister(instr->value());
1887 __ testq(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001888 EmitBranch(instr, not_zero);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001889 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001890 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001891 XMMRegister reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001892 XMMRegister xmm_scratch = double_scratch0();
1893 __ xorps(xmm_scratch, xmm_scratch);
1894 __ ucomisd(reg, xmm_scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001895 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001896 } else {
1897 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001898 Register reg = ToRegister(instr->value());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001899 HType type = instr->hydrogen()->value()->type();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001900 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001901 ASSERT(!info()->IsStub());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001902 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001903 EmitBranch(instr, equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001904 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001905 ASSERT(!info()->IsStub());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001906 __ SmiCompare(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001907 EmitBranch(instr, not_equal);
1908 } else if (type.IsJSArray()) {
1909 ASSERT(!info()->IsStub());
1910 EmitBranch(instr, no_condition);
1911 } else if (type.IsHeapNumber()) {
1912 ASSERT(!info()->IsStub());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001913 XMMRegister xmm_scratch = double_scratch0();
1914 __ xorps(xmm_scratch, xmm_scratch);
1915 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001916 EmitBranch(instr, not_equal);
1917 } else if (type.IsString()) {
1918 ASSERT(!info()->IsStub());
1919 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1920 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001921 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001922 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1923 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001924 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001925
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001926 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1927 // undefined -> false.
1928 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001929 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001930 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001931 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1932 // true -> true.
1933 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001934 __ j(equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001935 // false -> false.
1936 __ CompareRoot(reg, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001937 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001938 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001939 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1940 // 'null' -> false.
1941 __ CompareRoot(reg, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001942 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001943 }
1944
1945 if (expected.Contains(ToBooleanStub::SMI)) {
1946 // Smis: 0 -> false, all other -> true.
1947 __ Cmp(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001948 __ j(equal, instr->FalseLabel(chunk_));
1949 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001950 } else if (expected.NeedsMap()) {
1951 // If we need a map later and have a Smi -> deopt.
1952 __ testb(reg, Immediate(kSmiTagMask));
1953 DeoptimizeIf(zero, instr->environment());
1954 }
1955
1956 const Register map = kScratchRegister;
1957 if (expected.NeedsMap()) {
1958 __ movq(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001959
1960 if (expected.CanBeUndetectable()) {
1961 // Undetectable -> false.
1962 __ testb(FieldOperand(map, Map::kBitFieldOffset),
1963 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001964 __ j(not_zero, instr->FalseLabel(chunk_));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001965 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001966 }
1967
1968 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1969 // spec object -> true.
1970 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001971 __ j(above_equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001972 }
1973
1974 if (expected.Contains(ToBooleanStub::STRING)) {
1975 // String value -> false iff empty.
1976 Label not_string;
1977 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
1978 __ j(above_equal, &not_string, Label::kNear);
1979 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001980 __ j(not_zero, instr->TrueLabel(chunk_));
1981 __ jmp(instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001982 __ bind(&not_string);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001983 }
1984
danno@chromium.orgc16e8282013-08-12 16:17:40 +00001985 if (expected.Contains(ToBooleanStub::SYMBOL)) {
1986 // Symbol value -> true.
1987 __ CmpInstanceType(map, SYMBOL_TYPE);
1988 __ j(equal, instr->TrueLabel(chunk_));
1989 }
1990
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001991 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1992 // heap number -> false iff +0, -0, or NaN.
1993 Label not_heap_number;
1994 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
1995 __ j(not_equal, &not_heap_number, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001996 XMMRegister xmm_scratch = double_scratch0();
1997 __ xorps(xmm_scratch, xmm_scratch);
1998 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001999 __ j(zero, instr->FalseLabel(chunk_));
2000 __ jmp(instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002001 __ bind(&not_heap_number);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002002 }
2003
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002004 if (!expected.IsGeneric()) {
2005 // We've seen something for the first time -> deopt.
2006 // This can only happen if we are not generic already.
2007 DeoptimizeIf(no_condition, instr->environment());
2008 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002009 }
2010 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002011}
2012
2013
ager@chromium.org04921a82011-06-27 13:21:41 +00002014void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002015 if (!IsNextEmittedBlock(block)) {
2016 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002017 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002018}
2019
2020
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002021void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002022 EmitGoto(instr->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002023}
2024
2025
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002026inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002027 Condition cond = no_condition;
2028 switch (op) {
2029 case Token::EQ:
2030 case Token::EQ_STRICT:
2031 cond = equal;
2032 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002033 case Token::NE:
2034 case Token::NE_STRICT:
2035 cond = not_equal;
2036 break;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002037 case Token::LT:
2038 cond = is_unsigned ? below : less;
2039 break;
2040 case Token::GT:
2041 cond = is_unsigned ? above : greater;
2042 break;
2043 case Token::LTE:
2044 cond = is_unsigned ? below_equal : less_equal;
2045 break;
2046 case Token::GTE:
2047 cond = is_unsigned ? above_equal : greater_equal;
2048 break;
2049 case Token::IN:
2050 case Token::INSTANCEOF:
2051 default:
2052 UNREACHABLE();
2053 }
2054 return cond;
2055}
2056
2057
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002058void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002059 LOperand* left = instr->left();
2060 LOperand* right = instr->right();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002061 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002062
2063 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2064 // We can statically evaluate the comparison.
2065 double left_val = ToDouble(LConstantOperand::cast(left));
2066 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002067 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2068 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002069 EmitGoto(next_block);
2070 } else {
2071 if (instr->is_double()) {
2072 // Don't base result on EFLAGS when a NaN is involved. Instead
2073 // jump to the false block.
2074 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002075 __ j(parity_even, instr->FalseLabel(chunk_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002076 } else {
2077 int32_t value;
2078 if (right->IsConstantOperand()) {
2079 value = ToInteger32(LConstantOperand::cast(right));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002080 if (instr->hydrogen_value()->representation().IsSmi()) {
2081 __ Cmp(ToRegister(left), Smi::FromInt(value));
2082 } else {
2083 __ cmpl(ToRegister(left), Immediate(value));
2084 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002085 } else if (left->IsConstantOperand()) {
2086 value = ToInteger32(LConstantOperand::cast(left));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002087 if (instr->hydrogen_value()->representation().IsSmi()) {
2088 if (right->IsRegister()) {
2089 __ Cmp(ToRegister(right), Smi::FromInt(value));
2090 } else {
2091 __ Cmp(ToOperand(right), Smi::FromInt(value));
2092 }
2093 } else if (right->IsRegister()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002094 __ cmpl(ToRegister(right), Immediate(value));
2095 } else {
2096 __ cmpl(ToOperand(right), Immediate(value));
2097 }
2098 // We transposed the operands. Reverse the condition.
2099 cc = ReverseCondition(cc);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002100 } else if (instr->hydrogen_value()->representation().IsSmi()) {
2101 if (right->IsRegister()) {
2102 __ cmpq(ToRegister(left), ToRegister(right));
2103 } else {
2104 __ cmpq(ToRegister(left), ToOperand(right));
2105 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002106 } else {
2107 if (right->IsRegister()) {
2108 __ cmpl(ToRegister(left), ToRegister(right));
2109 } else {
2110 __ cmpl(ToRegister(left), ToOperand(right));
2111 }
2112 }
2113 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002114 EmitBranch(instr, cc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002115 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002116}
2117
2118
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002119void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002120 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002121
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002122 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002123 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002124 __ Cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002125 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002126 Register right = ToRegister(instr->right());
2127 __ cmpq(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002128 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002129 EmitBranch(instr, equal);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002130}
2131
2132
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002133void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2134 if (instr->hydrogen()->representation().IsTagged()) {
2135 Register input_reg = ToRegister(instr->object());
2136 __ Cmp(input_reg, factory()->the_hole_value());
2137 EmitBranch(instr, equal);
2138 return;
2139 }
2140
2141 XMMRegister input_reg = ToDoubleRegister(instr->object());
2142 __ ucomisd(input_reg, input_reg);
2143 EmitFalseBranch(instr, parity_odd);
2144
2145 __ subq(rsp, Immediate(kDoubleSize));
2146 __ movsd(MemOperand(rsp, 0), input_reg);
2147 __ addq(rsp, Immediate(kDoubleSize));
2148
2149 int offset = sizeof(kHoleNanUpper32);
2150 __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32));
2151 EmitBranch(instr, equal);
2152}
2153
2154
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002155Condition LCodeGen::EmitIsObject(Register input,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002156 Label* is_not_object,
2157 Label* is_object) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002158 ASSERT(!input.is(kScratchRegister));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002159
2160 __ JumpIfSmi(input, is_not_object);
2161
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002162 __ CompareRoot(input, Heap::kNullValueRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002163 __ j(equal, is_object);
2164
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002165 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002166 // Undetectable objects behave like undefined.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002167 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002168 Immediate(1 << Map::kIsUndetectable));
2169 __ j(not_zero, is_not_object);
2170
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002171 __ movzxbl(kScratchRegister,
2172 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002173 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002174 __ j(below, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002175 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002176 return below_equal;
2177}
2178
2179
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002180void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002181 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002182
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002183 Condition true_cond = EmitIsObject(
2184 reg, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002185
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002186 EmitBranch(instr, true_cond);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002187}
2188
2189
erikcorry0ad885c2011-11-21 13:51:57 +00002190Condition LCodeGen::EmitIsString(Register input,
2191 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002192 Label* is_not_string,
2193 SmiCheck check_needed = INLINE_SMI_CHECK) {
2194 if (check_needed == INLINE_SMI_CHECK) {
2195 __ JumpIfSmi(input, is_not_string);
2196 }
2197
erikcorry0ad885c2011-11-21 13:51:57 +00002198 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2199
2200 return cond;
2201}
2202
2203
2204void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002205 Register reg = ToRegister(instr->value());
2206 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002207
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002208 SmiCheck check_needed =
2209 instr->hydrogen()->value()->IsHeapObject()
2210 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erikcorry0ad885c2011-11-21 13:51:57 +00002211
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002212 Condition true_cond = EmitIsString(
2213 reg, temp, instr->FalseLabel(chunk_), check_needed);
erikcorry0ad885c2011-11-21 13:51:57 +00002214
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002215 EmitBranch(instr, true_cond);
erikcorry0ad885c2011-11-21 13:51:57 +00002216}
2217
2218
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002219void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002220 Condition is_smi;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002221 if (instr->value()->IsRegister()) {
2222 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002223 is_smi = masm()->CheckSmi(input);
2224 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002225 Operand input = ToOperand(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002226 is_smi = masm()->CheckSmi(input);
2227 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002228 EmitBranch(instr, is_smi);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002229}
2230
2231
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002232void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002233 Register input = ToRegister(instr->value());
2234 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002235
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002236 if (!instr->hydrogen()->value()->IsHeapObject()) {
2237 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2238 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002239 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
2240 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
2241 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002242 EmitBranch(instr, not_zero);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002243}
2244
2245
erikcorry0ad885c2011-11-21 13:51:57 +00002246void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2247 Token::Value op = instr->op();
erikcorry0ad885c2011-11-21 13:51:57 +00002248
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002249 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002250 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2251
2252 Condition condition = TokenToCondition(op, false);
2253 __ testq(rax, rax);
2254
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002255 EmitBranch(instr, condition);
erikcorry0ad885c2011-11-21 13:51:57 +00002256}
2257
2258
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002259static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002260 InstanceType from = instr->from();
2261 InstanceType to = instr->to();
2262 if (from == FIRST_TYPE) return to;
2263 ASSERT(from == to || to == LAST_TYPE);
2264 return from;
2265}
2266
2267
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002268static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002269 InstanceType from = instr->from();
2270 InstanceType to = instr->to();
2271 if (from == to) return equal;
2272 if (to == LAST_TYPE) return above_equal;
2273 if (from == FIRST_TYPE) return below_equal;
2274 UNREACHABLE();
2275 return equal;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002276}
2277
2278
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002279void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002280 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002281
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002282 if (!instr->hydrogen()->value()->IsHeapObject()) {
2283 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2284 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002285
2286 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002287 EmitBranch(instr, BranchCondition(instr->hydrogen()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002288}
2289
2290
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002291void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002292 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002293 Register result = ToRegister(instr->result());
2294
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002295 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002296
2297 __ movl(result, FieldOperand(input, String::kHashFieldOffset));
2298 ASSERT(String::kHashShift >= kSmiTagSize);
2299 __ IndexFromHash(result, result);
2300}
2301
2302
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002303void LCodeGen::DoHasCachedArrayIndexAndBranch(
2304 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002305 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002306
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002307 __ testl(FieldOperand(input, String::kHashFieldOffset),
2308 Immediate(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002309 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002310}
2311
2312
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002313// Branches to a label or falls through with the answer in the z flag.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002314// Trashes the temp register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002315void LCodeGen::EmitClassOfTest(Label* is_true,
2316 Label* is_false,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002317 Handle<String> class_name,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002318 Register input,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 Register temp,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002320 Register temp2) {
2321 ASSERT(!input.is(temp));
2322 ASSERT(!input.is(temp2));
2323 ASSERT(!temp.is(temp2));
2324
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002325 __ JumpIfSmi(input, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002326
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002327 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 // Assuming the following assertions, we can use the same compares to test
2329 // for both being a function type and being in the object type range.
2330 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2331 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2332 FIRST_SPEC_OBJECT_TYPE + 1);
2333 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2334 LAST_SPEC_OBJECT_TYPE - 1);
2335 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2336 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2337 __ j(below, is_false);
2338 __ j(equal, is_true);
2339 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2340 __ j(equal, is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002341 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002342 // Faster code path to avoid two compares: subtract lower bound from the
2343 // actual type and do a signed compare with the width of the type range.
2344 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002345 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
2346 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2347 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2348 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002349 __ j(above, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002350 }
2351
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002352 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002353 // Check if the constructor in the map is a function.
2354 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset));
2355
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002356 // Objects with a non-function constructor have class 'Object'.
2357 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002358 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002359 __ j(not_equal, is_true);
2360 } else {
2361 __ j(not_equal, is_false);
2362 }
2363
2364 // temp now contains the constructor function. Grab the
2365 // instance class name from there.
2366 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2367 __ movq(temp, FieldOperand(temp,
2368 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002369 // The class name we are testing against is internalized since it's a literal.
2370 // The name in the constructor is internalized because of the way the context
2371 // is booted. This routine isn't expected to work for random API-created
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002372 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002373 // syntax. Since both sides are internalized it is sufficient to use an
2374 // identity comparison.
2375 ASSERT(class_name->IsInternalizedString());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002376 __ Cmp(temp, class_name);
2377 // End with the answer in the z flag.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002378}
2379
2380
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002381void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002382 Register input = ToRegister(instr->value());
2383 Register temp = ToRegister(instr->temp());
2384 Register temp2 = ToRegister(instr->temp2());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002385 Handle<String> class_name = instr->hydrogen()->class_name();
2386
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002387 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2388 class_name, input, temp, temp2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002389
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002390 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002391}
2392
2393
2394void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002395 Register reg = ToRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002396
2397 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002398 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002399}
2400
2401
2402void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002403 InstanceofStub stub(InstanceofStub::kNoFlags);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002404 __ push(ToRegister(instr->left()));
2405 __ push(ToRegister(instr->right()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002406 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002407 Label true_value, done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002408 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002409 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002410 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002411 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002412 __ bind(&true_value);
2413 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2414 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002415}
2416
2417
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002418void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002419 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002420 public:
2421 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2422 LInstanceOfKnownGlobal* instr)
2423 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002424 virtual void Generate() V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002425 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002426 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002427 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002428 Label* map_check() { return &map_check_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002429 private:
2430 LInstanceOfKnownGlobal* instr_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002431 Label map_check_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002432 };
2433
2434
2435 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002436 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002437
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002438 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002439 Register object = ToRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002440
2441 // A Smi is not an instance of anything.
2442 __ JumpIfSmi(object, &false_result);
2443
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002444 // This is the inlined call site instanceof cache. The two occurences of the
2445 // hole value will be patched to the last map/result pair generated by the
2446 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002447 Label cache_miss;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002448 // Use a temp register to avoid memory operands with variable lengths.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002449 Register map = ToRegister(instr->temp());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002450 __ movq(map, FieldOperand(object, HeapObject::kMapOffset));
2451 __ bind(deferred->map_check()); // Label for calculating code patching.
danno@chromium.org41728482013-06-12 22:31:22 +00002452 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
2453 __ movq(kScratchRegister, cache_cell, RelocInfo::CELL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002454 __ cmpq(map, Operand(kScratchRegister, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002455 __ j(not_equal, &cache_miss, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002456 // Patched to load either true or false.
2457 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
2458#ifdef DEBUG
2459 // Check that the code size between patch label and patch sites is invariant.
2460 Label end_of_patched_code;
2461 __ bind(&end_of_patched_code);
2462 ASSERT(true);
2463#endif
2464 __ jmp(&done);
2465
2466 // The inlined call site cache did not match. Check for null and string
2467 // before calling the deferred code.
2468 __ bind(&cache_miss); // Null is not an instance of anything.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002469 __ CompareRoot(object, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002470 __ j(equal, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002471
2472 // String values are not instances of anything.
2473 __ JumpIfNotString(object, kScratchRegister, deferred->entry());
2474
2475 __ bind(&false_result);
2476 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2477
2478 __ bind(deferred->exit());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002479 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002480}
2481
2482
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002483void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2484 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002485 {
2486 PushSafepointRegistersScope scope(this);
2487 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
2488 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck);
2489 InstanceofStub stub(flags);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002490
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002491 __ push(ToRegister(instr->value()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002492 __ Push(instr->function());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002493
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002494 static const int kAdditionalDelta = 10;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002495 int delta =
2496 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002497 ASSERT(delta >= 0);
2498 __ push_imm32(delta);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002499
2500 // We are pushing three values on the stack but recording a
2501 // safepoint with two arguments because stub is going to
2502 // remove the third argument from the stack before jumping
2503 // to instanceof builtin on the slow path.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002504 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002505 RelocInfo::CODE_TARGET,
2506 instr,
2507 RECORD_SAFEPOINT_WITH_REGISTERS,
2508 2);
2509 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002510 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002511 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002512 // Move result to a register that survives the end of the
2513 // PushSafepointRegisterScope.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002514 __ movq(kScratchRegister, rax);
2515 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002516 __ testq(kScratchRegister, kScratchRegister);
2517 Label load_false;
2518 Label done;
2519 __ j(not_zero, &load_false);
2520 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
2521 __ jmp(&done);
2522 __ bind(&load_false);
2523 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2524 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002525}
2526
2527
2528void LCodeGen::DoCmpT(LCmpT* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002529 Token::Value op = instr->op();
2530
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002531 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002532 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2533
2534 Condition condition = TokenToCondition(op, false);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002535 Label true_value, done;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002536 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002537 __ j(condition, &true_value, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002538 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002539 __ jmp(&done, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002540 __ bind(&true_value);
2541 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2542 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002543}
2544
2545
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002546void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002547 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002548 // Preserve the return value on the stack and rely on the runtime
2549 // call to return the value in the same register.
2550 __ push(rax);
2551 __ CallRuntime(Runtime::kTraceExit, 1);
2552 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002553 if (info()->saves_caller_doubles()) {
2554 ASSERT(NeedsEagerFrame());
2555 BitVector* doubles = chunk()->allocated_double_registers();
2556 BitVector::Iterator save_iterator(doubles);
2557 int count = 0;
2558 while (!save_iterator.Done()) {
2559 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
2560 MemOperand(rsp, count * kDoubleSize));
2561 save_iterator.Advance();
2562 count++;
2563 }
2564 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002565 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002566 if (NeedsEagerFrame()) {
2567 __ movq(rsp, rbp);
2568 __ pop(rbp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002569 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002570 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002571 if (instr->has_constant_parameter_count()) {
2572 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
2573 rcx);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002574 } else {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002575 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002576 // The argument count parameter is a smi
2577 __ SmiToInteger32(reg, reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002578 Register return_addr_reg = reg.is(rcx) ? rbx : rcx;
danno@chromium.org59400602013-08-13 17:09:37 +00002579 __ PopReturnAddressTo(return_addr_reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002580 __ shl(reg, Immediate(kPointerSizeLog2));
2581 __ addq(rsp, reg);
2582 __ jmp(return_addr_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002583 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002584 if (no_frame_start != -1) {
2585 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2586 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002587}
2588
2589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002590void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002591 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002592 __ LoadGlobalCell(result, instr->hydrogen()->cell().handle());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002593 if (instr->hydrogen()->RequiresHoleCheck()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002594 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2595 DeoptimizeIf(equal, instr->environment());
2596 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002597}
2598
2599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002600void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2601 ASSERT(ToRegister(instr->global_object()).is(rax));
2602 ASSERT(ToRegister(instr->result()).is(rax));
2603
2604 __ Move(rcx, instr->name());
2605 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET :
2606 RelocInfo::CODE_TARGET_CONTEXT;
2607 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2608 CallCode(ic, mode, instr);
2609}
2610
2611
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002612void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002613 Register value = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002614 Handle<Cell> cell_handle = instr->hydrogen()->cell().handle();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002615
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002616 // If the cell we are storing to contains the hole it could have
2617 // been deleted from the property dictionary. In that case, we need
2618 // to update the property details in the property dictionary to mark
2619 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002620 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002621 // We have a temp because CompareRoot might clobber kScratchRegister.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002622 Register cell = ToRegister(instr->temp());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002623 ASSERT(!value.is(cell));
danno@chromium.org41728482013-06-12 22:31:22 +00002624 __ movq(cell, cell_handle, RelocInfo::CELL);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002625 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002626 DeoptimizeIf(equal, instr->environment());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002627 // Store the value.
2628 __ movq(Operand(cell, 0), value);
2629 } else {
2630 // Store the value.
danno@chromium.org41728482013-06-12 22:31:22 +00002631 __ movq(kScratchRegister, cell_handle, RelocInfo::CELL);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002632 __ movq(Operand(kScratchRegister, 0), value);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002633 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002634 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002635}
2636
2637
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002638void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2639 ASSERT(ToRegister(instr->global_object()).is(rdx));
2640 ASSERT(ToRegister(instr->value()).is(rax));
2641
2642 __ Move(rcx, instr->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002643 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002644 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2645 : isolate()->builtins()->StoreIC_Initialize();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002646 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2647}
2648
2649
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002650void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002651 Register context = ToRegister(instr->context());
2652 Register result = ToRegister(instr->result());
2653 __ movq(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002654 if (instr->hydrogen()->RequiresHoleCheck()) {
2655 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002656 if (instr->hydrogen()->DeoptimizesOnHole()) {
2657 DeoptimizeIf(equal, instr->environment());
2658 } else {
2659 Label is_not_hole;
2660 __ j(not_equal, &is_not_hole, Label::kNear);
2661 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2662 __ bind(&is_not_hole);
2663 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002664 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002665}
2666
2667
2668void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2669 Register context = ToRegister(instr->context());
2670 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002671
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002672 Operand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002673
2674 Label skip_assignment;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002675 if (instr->hydrogen()->RequiresHoleCheck()) {
2676 __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002677 if (instr->hydrogen()->DeoptimizesOnHole()) {
2678 DeoptimizeIf(equal, instr->environment());
2679 } else {
2680 __ j(not_equal, &skip_assignment);
2681 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002682 }
2683 __ movq(target, value);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002684
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002685 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002686 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002687 instr->hydrogen()->value()->IsHeapObject()
2688 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002689 int offset = Context::SlotOffset(instr->slot_index());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002690 Register scratch = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002691 __ RecordWriteContextSlot(context,
2692 offset,
2693 value,
2694 scratch,
2695 kSaveFPRegs,
2696 EMIT_REMEMBERED_SET,
2697 check_needed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002698 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002699
2700 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002701}
2702
2703
2704void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002705 HObjectAccess access = instr->hydrogen()->access();
2706 int offset = access.offset();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002707
2708 if (access.IsExternalMemory()) {
2709 Register result = ToRegister(instr->result());
2710 if (instr->object()->IsConstantOperand()) {
2711 ASSERT(result.is(rax));
2712 __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
2713 } else {
2714 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002715 __ Load(result, MemOperand(object, offset), access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002716 }
2717 return;
2718 }
2719
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002720 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002721 if (FLAG_track_double_fields &&
2722 instr->hydrogen()->representation().IsDouble()) {
2723 XMMRegister result = ToDoubleRegister(instr->result());
2724 __ movsd(result, FieldOperand(object, offset));
2725 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002726 }
2727
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002728 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002729 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002730 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002731 object = result;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002732 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002733 __ Load(result, FieldOperand(object, offset), access.representation());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002734}
2735
2736
2737void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002738 ASSERT(ToRegister(instr->object()).is(rax));
2739 ASSERT(ToRegister(instr->result()).is(rax));
2740
2741 __ Move(rcx, instr->name());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002742 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002743 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002744}
2745
2746
2747void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002748 Register function = ToRegister(instr->function());
2749 Register result = ToRegister(instr->result());
2750
2751 // Check that the function really is a function.
2752 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2753 DeoptimizeIf(not_equal, instr->environment());
2754
2755 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002756 Label non_instance;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002757 __ testb(FieldOperand(result, Map::kBitFieldOffset),
2758 Immediate(1 << Map::kHasNonInstancePrototype));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002759 __ j(not_zero, &non_instance, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002760
2761 // Get the prototype or initial map from the function.
2762 __ movq(result,
2763 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2764
2765 // Check that the function has a prototype or an initial map.
2766 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2767 DeoptimizeIf(equal, instr->environment());
2768
2769 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002770 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002771 __ CmpObjectType(result, MAP_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002772 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002773
2774 // Get the prototype from the initial map.
2775 __ movq(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002776 __ jmp(&done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002777
2778 // Non-instance prototype: Fetch prototype from constructor field
2779 // in the function's map.
2780 __ bind(&non_instance);
2781 __ movq(result, FieldOperand(result, Map::kConstructorOffset));
2782
2783 // All done.
2784 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002785}
2786
2787
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002788void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
2789 Register result = ToRegister(instr->result());
2790 __ LoadRoot(result, instr->index());
2791}
2792
2793
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002794void LCodeGen::DoLoadExternalArrayPointer(
2795 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002796 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002797 Register input = ToRegister(instr->object());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002798 __ movq(result, FieldOperand(input,
2799 ExternalPixelArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002800}
2801
2802
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002803void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002804 Register arguments = ToRegister(instr->arguments());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002805 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002806
2807 if (instr->length()->IsConstantOperand() &&
2808 instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002809 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2810 int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length()));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002811 StackArgumentsAccessor args(arguments, const_length,
2812 ARGUMENTS_DONT_CONTAIN_RECEIVER);
2813 __ movq(result, args.GetArgumentOperand(const_index));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002814 } else {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002815 Register length = ToRegister(instr->length());
2816 // There are two words between the frame pointer and the last argument.
2817 // Subtracting from length accounts for one of them add one more.
2818 if (instr->index()->IsRegister()) {
2819 __ subl(length, ToRegister(instr->index()));
2820 } else {
2821 __ subl(length, ToOperand(instr->index()));
2822 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002823 StackArgumentsAccessor args(arguments, length,
2824 ARGUMENTS_DONT_CONTAIN_RECEIVER);
2825 __ movq(result, args.GetArgumentOperand(0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002826 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002827}
2828
2829
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002830void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
2831 ElementsKind elements_kind = instr->elements_kind();
2832 LOperand* key = instr->key();
2833 if (!key->IsConstantOperand()) {
2834 Register key_reg = ToRegister(key);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002835 // Even though the HLoad/StoreKeyed (in this case) instructions force
2836 // the input representation for the key to be an integer, the input
2837 // gets replaced during bound check elimination with the index argument
2838 // to the bounds check, which can be tagged, so that case must be
2839 // handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002840 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002841 // Sign extend key because it could be a 32 bit negative value
2842 // and the dehoisted address computation happens in 64 bits
2843 __ movsxlq(key_reg, key_reg);
2844 }
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002845 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002846 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002847 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002848 key,
2849 elements_kind,
2850 0,
2851 instr->additional_index()));
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002852
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002853 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002854 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002855 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002856 __ cvtss2sd(result, result);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002857 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002858 __ movsd(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002859 } else {
2860 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002861 switch (elements_kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002862 case EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002863 __ movsxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002864 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002865 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2866 case EXTERNAL_PIXEL_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002867 __ movzxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002868 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002869 case EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002870 __ movsxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002871 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002872 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002873 __ movzxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002874 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002875 case EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002876 __ movsxlq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002877 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002878 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002879 __ movl(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002880 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2881 __ testl(result, result);
2882 DeoptimizeIf(negative, instr->environment());
2883 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002884 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002885 case EXTERNAL_FLOAT_ELEMENTS:
2886 case EXTERNAL_DOUBLE_ELEMENTS:
2887 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002888 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002889 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002890 case FAST_HOLEY_ELEMENTS:
2891 case FAST_HOLEY_SMI_ELEMENTS:
2892 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002893 case DICTIONARY_ELEMENTS:
2894 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002895 UNREACHABLE();
2896 break;
2897 }
2898 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002899}
2900
2901
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002902void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
2903 XMMRegister result(ToDoubleRegister(instr->result()));
2904 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002905 if (!key->IsConstantOperand()) {
2906 Register key_reg = ToRegister(key);
2907 // Even though the HLoad/StoreKeyed instructions force the input
2908 // representation for the key to be an integer, the input gets replaced
2909 // during bound check elimination with the index argument to the bounds
2910 // check, which can be tagged, so that case must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002911 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002912 // Sign extend key because it could be a 32 bit negative value
2913 // and the dehoisted address computation happens in 64 bits
2914 __ movsxlq(key_reg, key_reg);
2915 }
2916 }
2917
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002918 if (instr->hydrogen()->RequiresHoleCheck()) {
2919 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2920 sizeof(kHoleNanLower32);
2921 Operand hole_check_operand = BuildFastArrayOperand(
2922 instr->elements(),
2923 key,
2924 FAST_DOUBLE_ELEMENTS,
2925 offset,
2926 instr->additional_index());
2927 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
2928 DeoptimizeIf(equal, instr->environment());
2929 }
2930
2931 Operand double_load_operand = BuildFastArrayOperand(
2932 instr->elements(),
2933 key,
2934 FAST_DOUBLE_ELEMENTS,
2935 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
2936 instr->additional_index());
2937 __ movsd(result, double_load_operand);
2938}
2939
2940
2941void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
2942 Register result = ToRegister(instr->result());
2943 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002944 if (!key->IsConstantOperand()) {
2945 Register key_reg = ToRegister(key);
2946 // Even though the HLoad/StoreKeyedFastElement instructions force
2947 // the input representation for the key to be an integer, the input
2948 // gets replaced during bound check elimination with the index
2949 // argument to the bounds check, which can be tagged, so that
2950 // case must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002951 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002952 // Sign extend key because it could be a 32 bit negative value
2953 // and the dehoisted address computation happens in 64 bits
2954 __ movsxlq(key_reg, key_reg);
2955 }
2956 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002957
2958 // Load the result.
2959 __ movq(result,
2960 BuildFastArrayOperand(instr->elements(),
2961 key,
2962 FAST_ELEMENTS,
2963 FixedArray::kHeaderSize - kHeapObjectTag,
2964 instr->additional_index()));
2965
2966 // Check for the hole value.
2967 if (instr->hydrogen()->RequiresHoleCheck()) {
2968 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
2969 Condition smi = __ CheckSmi(result);
2970 DeoptimizeIf(NegateCondition(smi), instr->environment());
2971 } else {
2972 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2973 DeoptimizeIf(equal, instr->environment());
2974 }
2975 }
2976}
2977
2978
2979void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
2980 if (instr->is_external()) {
2981 DoLoadKeyedExternalArray(instr);
2982 } else if (instr->hydrogen()->representation().IsDouble()) {
2983 DoLoadKeyedFixedDoubleArray(instr);
2984 } else {
2985 DoLoadKeyedFixedArray(instr);
2986 }
2987}
2988
2989
2990Operand LCodeGen::BuildFastArrayOperand(
2991 LOperand* elements_pointer,
2992 LOperand* key,
2993 ElementsKind elements_kind,
2994 uint32_t offset,
2995 uint32_t additional_index) {
2996 Register elements_pointer_reg = ToRegister(elements_pointer);
2997 int shift_size = ElementsKindToShiftSize(elements_kind);
2998 if (key->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002999 int32_t constant_value = ToInteger32(LConstantOperand::cast(key));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003000 if (constant_value & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003001 Abort(kArrayIndexConstantValueTooBig);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003002 }
3003 return Operand(elements_pointer_reg,
3004 ((constant_value + additional_index) << shift_size)
3005 + offset);
3006 } else {
3007 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3008 return Operand(elements_pointer_reg,
3009 ToRegister(key),
3010 scale_factor,
3011 offset + (additional_index << shift_size));
3012 }
3013}
3014
3015
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003016void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003017 ASSERT(ToRegister(instr->object()).is(rdx));
3018 ASSERT(ToRegister(instr->key()).is(rax));
3019
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003020 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003021 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003022}
3023
3024
3025void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003026 Register result = ToRegister(instr->result());
3027
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003028 if (instr->hydrogen()->from_inlined()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003029 __ lea(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003030 } else {
3031 // Check for arguments adapter frame.
3032 Label done, adapted;
3033 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
3034 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
3035 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3036 __ j(equal, &adapted, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003037
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003038 // No arguments adaptor frame.
3039 __ movq(result, rbp);
3040 __ jmp(&done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003041
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003042 // Arguments adaptor frame present.
3043 __ bind(&adapted);
3044 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003045
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003046 // Result is the frame pointer for the frame if not adapted and for the real
3047 // frame below the adaptor frame if adapted.
3048 __ bind(&done);
3049 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003050}
3051
3052
3053void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003054 Register result = ToRegister(instr->result());
3055
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003056 Label done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003057
3058 // If no arguments adaptor frame the number of arguments is fixed.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003059 if (instr->elements()->IsRegister()) {
3060 __ cmpq(rbp, ToRegister(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003061 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003062 __ cmpq(rbp, ToOperand(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003063 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003064 __ movl(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003065 __ j(equal, &done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003066
3067 // Arguments adaptor frame present. Get argument length from there.
3068 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003069 __ SmiToInteger32(result,
3070 Operand(result,
3071 ArgumentsAdaptorFrameConstants::kLengthOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003072
3073 // Argument length is in result register.
3074 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003075}
3076
3077
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003078void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003079 Register receiver = ToRegister(instr->receiver());
3080 Register function = ToRegister(instr->function());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003081
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003082 // If the receiver is null or undefined, we have to pass the global
3083 // object as a receiver to normal functions. Values have to be
3084 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003085 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003086
3087 // Do not transform the receiver to object for strict mode
3088 // functions.
3089 __ movq(kScratchRegister,
3090 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3091 __ testb(FieldOperand(kScratchRegister,
3092 SharedFunctionInfo::kStrictModeByteOffset),
3093 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
3094 __ j(not_equal, &receiver_ok, Label::kNear);
3095
3096 // Do not transform the receiver to object for builtins.
3097 __ testb(FieldOperand(kScratchRegister,
3098 SharedFunctionInfo::kNativeByteOffset),
3099 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
3100 __ j(not_equal, &receiver_ok, Label::kNear);
3101
3102 // Normal function. Replace undefined or null with global receiver.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003103 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003104 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003105 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003106 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003107
3108 // The receiver should be a JS object.
3109 Condition is_smi = __ CheckSmi(receiver);
3110 DeoptimizeIf(is_smi, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003111 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003112 DeoptimizeIf(below, instr->environment());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003113 __ jmp(&receiver_ok, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003114
3115 __ bind(&global_object);
3116 // TODO(kmillikin): We have a hydrogen value for the global object. See
3117 // if it's better to use it than to explicitly fetch it from the context
3118 // here.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003119 __ movq(receiver, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003120 __ movq(receiver,
3121 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003122 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003123}
3124
3125
3126void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3127 Register receiver = ToRegister(instr->receiver());
3128 Register function = ToRegister(instr->function());
3129 Register length = ToRegister(instr->length());
3130 Register elements = ToRegister(instr->elements());
3131 ASSERT(receiver.is(rax)); // Used for parameter count.
3132 ASSERT(function.is(rdi)); // Required by InvokeFunction.
3133 ASSERT(ToRegister(instr->result()).is(rax));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003134
3135 // Copy the arguments to this function possibly from the
3136 // adaptor frame below it.
3137 const uint32_t kArgumentsLimit = 1 * KB;
3138 __ cmpq(length, Immediate(kArgumentsLimit));
3139 DeoptimizeIf(above, instr->environment());
3140
3141 __ push(receiver);
3142 __ movq(receiver, length);
3143
3144 // Loop through the arguments pushing them onto the execution
3145 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003146 Label invoke, loop;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003147 // length is a small non-negative integer, due to the test above.
3148 __ testl(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003149 __ j(zero, &invoke, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003150 __ bind(&loop);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003151 StackArgumentsAccessor args(elements, length,
3152 ARGUMENTS_DONT_CONTAIN_RECEIVER);
3153 __ push(args.GetArgumentOperand(0));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003154 __ decl(length);
3155 __ j(not_zero, &loop);
3156
3157 // Invoke the function.
3158 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003159 ASSERT(instr->HasPointerMap());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003160 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003161 SafepointGenerator safepoint_generator(
3162 this, pointers, Safepoint::kLazyDeopt);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003163 ParameterCount actual(rax);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003164 __ InvokeFunction(function, actual, CALL_FUNCTION,
3165 safepoint_generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003166 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003167}
3168
3169
3170void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003171 LOperand* argument = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00003172 EmitPushTaggedOperand(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003173}
3174
3175
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003176void LCodeGen::DoDrop(LDrop* instr) {
3177 __ Drop(instr->count());
3178}
3179
3180
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003181void LCodeGen::DoThisFunction(LThisFunction* instr) {
3182 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003183 __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003184}
3185
3186
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003187void LCodeGen::DoContext(LContext* instr) {
3188 Register result = ToRegister(instr->result());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003189 __ movq(result, rsi);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003190}
3191
3192
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003193void LCodeGen::DoOuterContext(LOuterContext* instr) {
3194 Register context = ToRegister(instr->context());
3195 Register result = ToRegister(instr->result());
3196 __ movq(result,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003197 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003198}
3199
3200
yangguo@chromium.org56454712012-02-16 15:33:53 +00003201void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3202 __ push(rsi); // The context is the first argument.
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003203 __ Push(instr->hydrogen()->pairs());
yangguo@chromium.org56454712012-02-16 15:33:53 +00003204 __ Push(Smi::FromInt(instr->hydrogen()->flags()));
3205 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3206}
3207
3208
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003209void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00003210 Register result = ToRegister(instr->result());
3211 __ movq(result, GlobalObjectOperand());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003212}
3213
3214
3215void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216 Register global = ToRegister(instr->global());
ager@chromium.org378b34e2011-01-28 08:04:38 +00003217 Register result = ToRegister(instr->result());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003218 __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003219}
3220
3221
3222void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003223 int formal_parameter_count,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003224 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003225 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003226 CallKind call_kind,
3227 RDIState rdi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003228 bool dont_adapt_arguments =
3229 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3230 bool can_invoke_directly =
3231 dont_adapt_arguments || formal_parameter_count == arity;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003232
3233 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003234
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003235 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003236 if (rdi_state == RDI_UNINITIALIZED) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003237 __ Move(rdi, function);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003238 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003239
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003240 // Change context.
3241 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003242
3243 // Set rax to arguments count if adaption is not needed. Assumes that rax
3244 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003245 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003246 __ Set(rax, arity);
3247 }
3248
3249 // Invoke function.
3250 __ SetCallKind(rcx, call_kind);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003251 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003252 __ CallSelf();
3253 } else {
3254 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
3255 }
3256
3257 // Set up deoptimization.
3258 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
3259 } else {
3260 // We need to adapt arguments.
3261 SafepointGenerator generator(
3262 this, pointers, Safepoint::kLazyDeopt);
3263 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003264 ParameterCount expected(formal_parameter_count);
3265 __ InvokeFunction(
3266 function, expected, count, CALL_FUNCTION, generator, call_kind);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003267 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003268
3269 // Restore context.
3270 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003271}
3272
3273
3274void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003275 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003276 CallKnownFunction(instr->hydrogen()->function(),
3277 instr->hydrogen()->formal_parameter_count(),
danno@chromium.org40cb8782011-05-25 07:58:50 +00003278 instr->arity(),
3279 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003280 CALL_AS_METHOD,
3281 RDI_UNINITIALIZED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003282}
3283
3284
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003285void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003286 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003287 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3288 Heap::kHeapNumberMapRootIndex);
3289 DeoptimizeIf(not_equal, instr->environment());
3290
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003291 Label slow, allocated, done;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003292 Register tmp = input_reg.is(rax) ? rcx : rax;
3293 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx;
3294
3295 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003296 PushSafepointRegistersScope scope(this);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003297
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003298 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3299 // Check the sign of the argument. If the argument is positive, just
3300 // return it. We do not need to patch the stack since |input| and
3301 // |result| are the same register and |input| will be restored
3302 // unchanged by popping safepoint registers.
3303 __ testl(tmp, Immediate(HeapNumber::kSignMask));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003304 __ j(zero, &done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003305
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003306 __ AllocateHeapNumber(tmp, tmp2, &slow);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003307 __ jmp(&allocated, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003308
3309 // Slow case: Call the runtime system to do the number allocation.
3310 __ bind(&slow);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003311 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003312 // Set the pointer to the new heap number in tmp.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003313 if (!tmp.is(rax)) __ movq(tmp, rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003314 // Restore input_reg after call to runtime.
3315 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3316
3317 __ bind(&allocated);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00003318 __ MoveDouble(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003319 __ shl(tmp2, Immediate(1));
3320 __ shr(tmp2, Immediate(1));
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00003321 __ MoveDouble(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003322 __ StoreToSafepointRegisterSlot(input_reg, tmp);
3323
3324 __ bind(&done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003325}
3326
3327
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003328void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003329 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003330 __ testl(input_reg, input_reg);
3331 Label is_positive;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003332 __ j(not_sign, &is_positive, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003333 __ negl(input_reg); // Sets flags.
3334 DeoptimizeIf(negative, instr->environment());
3335 __ bind(&is_positive);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003336}
3337
3338
danno@chromium.org59400602013-08-13 17:09:37 +00003339void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) {
3340 Register input_reg = ToRegister(instr->value());
3341 __ testq(input_reg, input_reg);
3342 Label is_positive;
3343 __ j(not_sign, &is_positive, Label::kNear);
3344 __ neg(input_reg); // Sets flags.
3345 DeoptimizeIf(negative, instr->environment());
3346 __ bind(&is_positive);
3347}
3348
3349
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003350void LCodeGen::DoMathAbs(LMathAbs* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003351 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003352 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003353 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003354 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003355 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003356 virtual void Generate() V8_OVERRIDE {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003357 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3358 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003359 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003360 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003361 LMathAbs* instr_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003362 };
3363
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003364 ASSERT(instr->value()->Equals(instr->result()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003365 Representation r = instr->hydrogen()->value()->representation();
3366
3367 if (r.IsDouble()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003368 XMMRegister scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003369 XMMRegister input_reg = ToDoubleRegister(instr->value());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003370 __ xorps(scratch, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003371 __ subsd(scratch, input_reg);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00003372 __ andps(input_reg, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003373 } else if (r.IsInteger32()) {
3374 EmitIntegerMathAbs(instr);
danno@chromium.org59400602013-08-13 17:09:37 +00003375 } else if (r.IsSmi()) {
3376 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003377 } else { // Tagged case.
3378 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003379 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003380 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003381 // Smi check.
3382 __ JumpIfNotSmi(input_reg, deferred->entry());
danno@chromium.org59400602013-08-13 17:09:37 +00003383 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003384 __ bind(deferred->exit());
3385 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003386}
3387
3388
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003389void LCodeGen::DoMathFloor(LMathFloor* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003390 XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003391 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003392 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003393
danno@chromium.org160a7b02011-04-18 15:51:38 +00003394 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003395 CpuFeatureScope scope(masm(), SSE4_1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003396 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3397 // Deoptimize if minus zero.
3398 __ movq(output_reg, input_reg);
3399 __ subq(output_reg, Immediate(1));
3400 DeoptimizeIf(overflow, instr->environment());
3401 }
3402 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3403 __ cvttsd2si(output_reg, xmm_scratch);
3404 __ cmpl(output_reg, Immediate(0x80000000));
3405 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003406 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003407 Label negative_sign, done;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003408 // Deoptimize on unordered.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003409 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3410 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003411 DeoptimizeIf(parity_even, instr->environment());
3412 __ j(below, &negative_sign, Label::kNear);
3413
danno@chromium.org160a7b02011-04-18 15:51:38 +00003414 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003415 // Check for negative zero.
3416 Label positive_sign;
3417 __ j(above, &positive_sign, Label::kNear);
3418 __ movmskpd(output_reg, input_reg);
3419 __ testq(output_reg, Immediate(1));
3420 DeoptimizeIf(not_zero, instr->environment());
3421 __ Set(output_reg, 0);
3422 __ jmp(&done);
3423 __ bind(&positive_sign);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003424 }
3425
3426 // Use truncating instruction (OK because input is positive).
3427 __ cvttsd2si(output_reg, input_reg);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003428 // Overflow is signalled with minint.
3429 __ cmpl(output_reg, Immediate(0x80000000));
3430 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003431 __ jmp(&done, Label::kNear);
3432
3433 // Non-zero negative reaches here.
3434 __ bind(&negative_sign);
3435 // Truncate, then compare and compensate.
3436 __ cvttsd2si(output_reg, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003437 __ Cvtlsi2sd(xmm_scratch, output_reg);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003438 __ ucomisd(input_reg, xmm_scratch);
3439 __ j(equal, &done, Label::kNear);
3440 __ subl(output_reg, Immediate(1));
3441 DeoptimizeIf(overflow, instr->environment());
3442
3443 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003444 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003445}
3446
3447
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003448void LCodeGen::DoMathRound(LMathRound* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003449 const XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003450 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003451 XMMRegister input_reg = ToDoubleRegister(instr->value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003452 static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
3453 static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003454
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003455 Label done, round_to_zero, below_one_half, do_not_compensate, restore;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003456 __ movq(kScratchRegister, one_half, RelocInfo::NONE64);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003457 __ movq(xmm_scratch, kScratchRegister);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003458 __ ucomisd(xmm_scratch, input_reg);
3459 __ j(above, &below_one_half);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003460
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003461 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3462 __ addsd(xmm_scratch, input_reg);
3463 __ cvttsd2si(output_reg, xmm_scratch);
3464 // Overflow is signalled with minint.
3465 __ cmpl(output_reg, Immediate(0x80000000));
3466 __ RecordComment("D2I conversion overflow");
3467 DeoptimizeIf(equal, instr->environment());
3468 __ jmp(&done);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003469
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003470 __ bind(&below_one_half);
3471 __ movq(kScratchRegister, minus_one_half, RelocInfo::NONE64);
3472 __ movq(xmm_scratch, kScratchRegister);
3473 __ ucomisd(xmm_scratch, input_reg);
3474 __ j(below_equal, &round_to_zero);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003475
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003476 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3477 // compare and compensate.
3478 __ movq(kScratchRegister, input_reg); // Back up input_reg.
3479 __ subsd(input_reg, xmm_scratch);
3480 __ cvttsd2si(output_reg, input_reg);
3481 // Catch minint due to overflow, and to prevent overflow when compensating.
3482 __ cmpl(output_reg, Immediate(0x80000000));
3483 __ RecordComment("D2I conversion overflow");
3484 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003485
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003486 __ Cvtlsi2sd(xmm_scratch, output_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003487 __ ucomisd(input_reg, xmm_scratch);
3488 __ j(equal, &restore, Label::kNear);
3489 __ subl(output_reg, Immediate(1));
3490 // No overflow because we already ruled out minint.
3491 __ bind(&restore);
3492 __ movq(input_reg, kScratchRegister); // Restore input_reg.
3493 __ jmp(&done);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003494
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003495 __ bind(&round_to_zero);
3496 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3497 // we can ignore the difference between a result of -0 and +0.
3498 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3499 __ movq(output_reg, input_reg);
3500 __ testq(output_reg, output_reg);
3501 __ RecordComment("Minus zero");
3502 DeoptimizeIf(negative, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003503 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003504 __ Set(output_reg, 0);
3505 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003506}
3507
3508
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003509void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003510 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003511 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3512 __ sqrtsd(input_reg, input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003513}
3514
3515
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003516void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003517 XMMRegister xmm_scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003518 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003519 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003520
3521 // Note that according to ECMA-262 15.8.2.13:
3522 // Math.pow(-Infinity, 0.5) == Infinity
3523 // Math.sqrt(-Infinity) == NaN
3524 Label done, sqrt;
3525 // Check base for -Infinity. According to IEEE-754, double-precision
3526 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00003527 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000), RelocInfo::NONE64);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003528 __ movq(xmm_scratch, kScratchRegister);
3529 __ ucomisd(xmm_scratch, input_reg);
3530 // Comparing -Infinity with NaN results in "unordered", which sets the
3531 // zero flag as if both were equal. However, it also sets the carry flag.
3532 __ j(not_equal, &sqrt, Label::kNear);
3533 __ j(carry, &sqrt, Label::kNear);
3534 // If input is -Infinity, return Infinity.
3535 __ xorps(input_reg, input_reg);
3536 __ subsd(input_reg, xmm_scratch);
3537 __ jmp(&done, Label::kNear);
3538
3539 // Square root.
3540 __ bind(&sqrt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003541 __ xorps(xmm_scratch, xmm_scratch);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003542 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
3543 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003544 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003545}
3546
3547
3548void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003549 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003550 // Having marked this as a call, we can use any registers.
3551 // Just make sure that the input/output registers are the expected ones.
3552
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003553 Register exponent = rdx;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003554 ASSERT(!instr->right()->IsRegister() ||
3555 ToRegister(instr->right()).is(exponent));
3556 ASSERT(!instr->right()->IsDoubleRegister() ||
3557 ToDoubleRegister(instr->right()).is(xmm1));
3558 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003559 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003560
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003561 if (exponent_type.IsSmi()) {
3562 MathPowStub stub(MathPowStub::TAGGED);
3563 __ CallStub(&stub);
3564 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003565 Label no_deopt;
3566 __ JumpIfSmi(exponent, &no_deopt);
3567 __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003568 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003569 __ bind(&no_deopt);
3570 MathPowStub stub(MathPowStub::TAGGED);
3571 __ CallStub(&stub);
3572 } else if (exponent_type.IsInteger32()) {
3573 MathPowStub stub(MathPowStub::INTEGER);
3574 __ CallStub(&stub);
3575 } else {
3576 ASSERT(exponent_type.IsDouble());
3577 MathPowStub stub(MathPowStub::DOUBLE);
3578 __ CallStub(&stub);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003579 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003580}
3581
3582
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003583void LCodeGen::DoRandom(LRandom* instr) {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003584 // Assert that register size is twice the size of each seed.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003585 static const int kSeedSize = sizeof(uint32_t);
3586 STATIC_ASSERT(kPointerSize == 2 * kSeedSize);
3587
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003588 // Load native context
3589 Register global_object = ToRegister(instr->global_object());
3590 Register native_context = global_object;
3591 __ movq(native_context, FieldOperand(
3592 global_object, GlobalObject::kNativeContextOffset));
3593
3594 // Load state (FixedArray of the native context's random seeds)
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003595 static const int kRandomSeedOffset =
3596 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003597 Register state = native_context;
3598 __ movq(state, FieldOperand(native_context, kRandomSeedOffset));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003599
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003600 // Load state[0].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003601 Register state0 = ToRegister(instr->scratch());
3602 __ movl(state0, FieldOperand(state, ByteArray::kHeaderSize));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003603 // Load state[1].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003604 Register state1 = ToRegister(instr->scratch2());
3605 __ movl(state1, FieldOperand(state, ByteArray::kHeaderSize + kSeedSize));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003606
3607 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003608 Register scratch3 = ToRegister(instr->scratch3());
3609 __ movzxwl(scratch3, state0);
3610 __ imull(scratch3, scratch3, Immediate(18273));
3611 __ shrl(state0, Immediate(16));
3612 __ addl(state0, scratch3);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003613 // Save state[0].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003614 __ movl(FieldOperand(state, ByteArray::kHeaderSize), state0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003615
3616 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003617 __ movzxwl(scratch3, state1);
3618 __ imull(scratch3, scratch3, Immediate(36969));
3619 __ shrl(state1, Immediate(16));
3620 __ addl(state1, scratch3);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003621 // Save state[1].
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003622 __ movl(FieldOperand(state, ByteArray::kHeaderSize + kSeedSize), state1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003623
3624 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003625 Register random = state0;
3626 __ shll(random, Immediate(14));
3627 __ andl(state1, Immediate(0x3FFFF));
3628 __ addl(random, state1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003629
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003630 // Convert 32 random bits in rax to 0.(32 random bits) in a double
3631 // by computing:
3632 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003633 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003634 XMMRegister scratch4 = double_scratch0();
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003635 __ movq(scratch3, V8_INT64_C(0x4130000000000000),
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00003636 RelocInfo::NONE64); // 1.0 x 2^20 as double
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003637 __ movq(scratch4, scratch3);
3638 __ movd(result, random);
3639 __ xorps(result, scratch4);
3640 __ subsd(result, scratch4);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003641}
3642
3643
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003644void LCodeGen::DoMathExp(LMathExp* instr) {
3645 XMMRegister input = ToDoubleRegister(instr->value());
3646 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003647 XMMRegister temp0 = double_scratch0();
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003648 Register temp1 = ToRegister(instr->temp1());
3649 Register temp2 = ToRegister(instr->temp2());
3650
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003651 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003652}
3653
3654
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003655void LCodeGen::DoMathLog(LMathLog* instr) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003656 ASSERT(instr->value()->Equals(instr->result()));
3657 XMMRegister input_reg = ToDoubleRegister(instr->value());
3658 XMMRegister xmm_scratch = double_scratch0();
3659 Label positive, done, zero;
3660 __ xorps(xmm_scratch, xmm_scratch);
3661 __ ucomisd(input_reg, xmm_scratch);
3662 __ j(above, &positive, Label::kNear);
3663 __ j(equal, &zero, Label::kNear);
3664 ExternalReference nan =
3665 ExternalReference::address_of_canonical_non_hole_nan();
3666 Operand nan_operand = masm()->ExternalOperand(nan);
3667 __ movsd(input_reg, nan_operand);
3668 __ jmp(&done, Label::kNear);
3669 __ bind(&zero);
3670 ExternalReference ninf =
3671 ExternalReference::address_of_negative_infinity();
3672 Operand ninf_operand = masm()->ExternalOperand(ninf);
3673 __ movsd(input_reg, ninf_operand);
3674 __ jmp(&done, Label::kNear);
3675 __ bind(&positive);
3676 __ fldln2();
3677 __ subq(rsp, Immediate(kDoubleSize));
3678 __ movsd(Operand(rsp, 0), input_reg);
3679 __ fld_d(Operand(rsp, 0));
3680 __ fyl2x();
3681 __ fstp_d(Operand(rsp, 0));
3682 __ movsd(input_reg, Operand(rsp, 0));
3683 __ addq(rsp, Immediate(kDoubleSize));
3684 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003685}
3686
3687
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003688void LCodeGen::DoMathTan(LMathTan* instr) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003689 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
3690 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3691 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003692 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003693}
3694
3695
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003696void LCodeGen::DoMathCos(LMathCos* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003697 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org5c297712011-03-10 14:17:25 +00003698 TranscendentalCacheStub stub(TranscendentalCache::COS,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003699 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003700 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003701}
3702
3703
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003704void LCodeGen::DoMathSin(LMathSin* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003705 ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
whesse@chromium.org5c297712011-03-10 14:17:25 +00003706 TranscendentalCacheStub stub(TranscendentalCache::SIN,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003707 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003708 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003709}
3710
3711
danno@chromium.org160a7b02011-04-18 15:51:38 +00003712void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3713 ASSERT(ToRegister(instr->function()).is(rdi));
3714 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003715
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003716 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3717 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003718 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003719 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3720 ParameterCount count(instr->arity());
3721 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3722 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
3723 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003724 CallKnownFunction(known_function,
3725 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003726 instr->arity(),
3727 instr,
3728 CALL_AS_METHOD,
3729 RDI_CONTAINS_TARGET);
3730 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003731}
3732
3733
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003734void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003735 ASSERT(ToRegister(instr->key()).is(rcx));
3736 ASSERT(ToRegister(instr->result()).is(rax));
3737
3738 int arity = instr->arity();
lrn@chromium.org34e60782011-09-15 07:25:40 +00003739 Handle<Code> ic =
3740 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003741 CallCode(ic, RelocInfo::CODE_TARGET, instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003742 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003743}
3744
3745
3746void LCodeGen::DoCallNamed(LCallNamed* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003747 ASSERT(ToRegister(instr->result()).is(rax));
3748
3749 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003750 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3751 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003752 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003753 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003754 CallCode(ic, mode, instr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003755 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003756}
3757
3758
3759void LCodeGen::DoCallFunction(LCallFunction* instr) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003760 ASSERT(ToRegister(instr->function()).is(rdi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003761 ASSERT(ToRegister(instr->result()).is(rax));
3762
3763 int arity = instr->arity();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003764 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003765 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003766 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003767}
3768
3769
3770void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003771 ASSERT(ToRegister(instr->result()).is(rax));
3772 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003773 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3774 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003775 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003776 __ Move(rcx, instr->name());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003777 CallCode(ic, mode, instr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003778 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003779}
3780
3781
3782void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003783 ASSERT(ToRegister(instr->result()).is(rax));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003784 CallKnownFunction(instr->hydrogen()->target(),
3785 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003786 instr->arity(),
3787 instr,
3788 CALL_AS_FUNCTION,
3789 RDI_UNINITIALIZED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003790}
3791
3792
3793void LCodeGen::DoCallNew(LCallNew* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003794 ASSERT(ToRegister(instr->constructor()).is(rdi));
ager@chromium.org378b34e2011-01-28 08:04:38 +00003795 ASSERT(ToRegister(instr->result()).is(rax));
3796
ager@chromium.org378b34e2011-01-28 08:04:38 +00003797 __ Set(rax, instr->arity());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003798 // No cell in ebx for construct type feedback in optimized code
3799 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
3800 __ Move(rbx, undefined_value);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003801 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003802 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003803}
3804
3805
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003806void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
3807 ASSERT(ToRegister(instr->constructor()).is(rdi));
3808 ASSERT(ToRegister(instr->result()).is(rax));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003809
3810 __ Set(rax, instr->arity());
3811 __ Move(rbx, instr->hydrogen()->property_cell());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003812 ElementsKind kind = instr->hydrogen()->elements_kind();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003813 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00003814 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003815 ? DISABLE_ALLOCATION_SITES
3816 : DONT_OVERRIDE;
3817 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003818
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003819 if (instr->arity() == 0) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003820 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003821 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3822 } else if (instr->arity() == 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00003823 Label done;
3824 if (IsFastPackedElementsKind(kind)) {
3825 Label packed_case;
3826 // We might need a change here
3827 // look at the first argument
3828 __ movq(rcx, Operand(rsp, 0));
3829 __ testq(rcx, rcx);
3830 __ j(zero, &packed_case);
3831
3832 ElementsKind holey_kind = GetHoleyElementsKind(kind);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003833 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
3834 override_mode);
danno@chromium.org41728482013-06-12 22:31:22 +00003835 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3836 __ jmp(&done);
3837 __ bind(&packed_case);
3838 }
3839
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003840 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003841 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.org41728482013-06-12 22:31:22 +00003842 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003843 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003844 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003845 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3846 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003847}
3848
3849
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003850void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003851 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003852}
3853
3854
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003855void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
3856 Register function = ToRegister(instr->function());
3857 Register code_object = ToRegister(instr->code_object());
3858 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
3859 __ movq(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
3860}
3861
3862
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003863void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3864 Register result = ToRegister(instr->result());
3865 Register base = ToRegister(instr->base_object());
3866 __ lea(result, Operand(base, instr->offset()));
3867}
3868
3869
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003870void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003871 Representation representation = instr->representation();
3872
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003873 HObjectAccess access = instr->hydrogen()->access();
3874 int offset = access.offset();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003875
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003876 if (access.IsExternalMemory()) {
3877 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3878 Register value = ToRegister(instr->value());
3879 if (instr->object()->IsConstantOperand()) {
3880 ASSERT(value.is(rax));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003881 ASSERT(!access.representation().IsSpecialization());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003882 LConstantOperand* object = LConstantOperand::cast(instr->object());
3883 __ store_rax(ToExternalReference(object));
3884 } else {
3885 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003886 __ Store(MemOperand(object, offset), value, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003887 }
3888 return;
3889 }
3890
3891 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003892 Handle<Map> transition = instr->transition();
3893
danno@chromium.orgf005df62013-04-30 16:36:45 +00003894 if (FLAG_track_fields && representation.IsSmi()) {
3895 if (instr->value()->IsConstantOperand()) {
3896 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003897 if (!IsSmiConstant(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003898 DeoptimizeIf(no_condition, instr->environment());
3899 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003900 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003901 } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
3902 if (instr->value()->IsConstantOperand()) {
3903 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
3904 if (IsInteger32Constant(operand_value)) {
3905 DeoptimizeIf(no_condition, instr->environment());
3906 }
3907 } else {
3908 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
3909 Register value = ToRegister(instr->value());
3910 Condition cc = masm()->CheckSmi(value);
3911 DeoptimizeIf(cc, instr->environment());
3912 }
3913 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003914 } else if (FLAG_track_double_fields && representation.IsDouble()) {
3915 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003916 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003917 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3918 XMMRegister value = ToDoubleRegister(instr->value());
3919 __ movsd(FieldOperand(object, offset), value);
3920 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003921 }
3922
danno@chromium.orgf005df62013-04-30 16:36:45 +00003923 if (!transition.is_null()) {
verwaest@chromium.org37141392012-05-31 13:27:02 +00003924 if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003925 __ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003926 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003927 Register temp = ToRegister(instr->temp());
danno@chromium.orgf005df62013-04-30 16:36:45 +00003928 __ Move(kScratchRegister, transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003929 __ movq(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister);
3930 // Update the write barrier for the map field.
3931 __ RecordWriteField(object,
3932 HeapObject::kMapOffset,
3933 kScratchRegister,
3934 temp,
3935 kSaveFPRegs,
3936 OMIT_REMEMBERED_SET,
3937 OMIT_SMI_CHECK);
3938 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003939 }
3940
3941 // Do the store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003942 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003943 instr->hydrogen()->value()->IsHeapObject()
3944 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003945
3946 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003947 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003948 write_register = ToRegister(instr->temp());
3949 __ movq(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
3950 }
3951
3952 if (instr->value()->IsConstantOperand()) {
3953 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003954 if (operand_value->IsRegister()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003955 Register value = ToRegister(operand_value);
3956 __ Store(FieldOperand(write_register, offset), value, representation);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003957 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003958 Handle<Object> handle_value = ToHandle(operand_value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003959 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003960 __ Move(FieldOperand(write_register, offset), handle_value);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003961 }
3962 } else {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003963 Register value = ToRegister(instr->value());
3964 __ Store(FieldOperand(write_register, offset), value, representation);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003965 }
3966
3967 if (instr->hydrogen()->NeedsWriteBarrier()) {
3968 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003969 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003970 // Update the write barrier for the object for in-object properties.
3971 __ RecordWriteField(write_register,
3972 offset,
3973 value,
3974 temp,
3975 kSaveFPRegs,
3976 EMIT_REMEMBERED_SET,
3977 check_needed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00003978 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003979}
3980
3981
3982void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003983 ASSERT(ToRegister(instr->object()).is(rdx));
3984 ASSERT(ToRegister(instr->value()).is(rax));
3985
3986 __ Move(rcx, instr->hydrogen()->name());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003987 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003988 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3989 : isolate()->builtins()->StoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003990 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3991}
3992
3993
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003994void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
3995 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
3996 Label done;
3997 __ j(NegateCondition(cc), &done, Label::kNear);
3998 __ int3();
3999 __ bind(&done);
4000 } else {
4001 DeoptimizeIf(cc, check->environment());
4002 }
4003}
4004
4005
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004006void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004007 if (instr->hydrogen()->skip_check()) return;
4008
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004009 if (instr->length()->IsRegister()) {
4010 Register reg = ToRegister(instr->length());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004011 if (!instr->hydrogen()->length()->representation().IsSmi()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004012 __ AssertZeroExtended(reg);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004013 }
4014 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004015 int32_t constant_index =
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004016 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004017 if (instr->hydrogen()->length()->representation().IsSmi()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004018 __ Cmp(reg, Smi::FromInt(constant_index));
4019 } else {
4020 __ cmpq(reg, Immediate(constant_index));
4021 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004022 } else {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004023 Register reg2 = ToRegister(instr->index());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004024 if (!instr->hydrogen()->index()->representation().IsSmi()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004025 __ AssertZeroExtended(reg2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004026 }
4027 __ cmpq(reg, reg2);
danno@chromium.orgb6451162011-08-17 14:33:23 +00004028 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004029 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004030 Operand length = ToOperand(instr->length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004031 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004032 int32_t constant_index =
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004033 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004034 if (instr->hydrogen()->length()->representation().IsSmi()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004035 __ Cmp(length, Smi::FromInt(constant_index));
4036 } else {
4037 __ cmpq(length, Immediate(constant_index));
4038 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004039 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004040 __ cmpq(length, ToRegister(instr->index()));
danno@chromium.orgb6451162011-08-17 14:33:23 +00004041 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004042 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004043 Condition condition =
4044 instr->hydrogen()->allow_equality() ? below : below_equal;
4045 ApplyCheckIf(condition, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004046}
4047
4048
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004049void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4050 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004051 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004052 if (!key->IsConstantOperand()) {
4053 Register key_reg = ToRegister(key);
4054 // Even though the HLoad/StoreKeyedFastElement instructions force
4055 // the input representation for the key to be an integer, the input
4056 // gets replaced during bound check elimination with the index
4057 // argument to the bounds check, which can be tagged, so that case
4058 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004059 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004060 // Sign extend key because it could be a 32 bit negative value
4061 // and the dehoisted address computation happens in 64 bits
4062 __ movsxlq(key_reg, key_reg);
4063 }
4064 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004065 Operand operand(BuildFastArrayOperand(
4066 instr->elements(),
4067 key,
4068 elements_kind,
4069 0,
4070 instr->additional_index()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004071
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004072 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4073 XMMRegister value(ToDoubleRegister(instr->value()));
4074 __ cvtsd2ss(value, value);
4075 __ movss(operand, value);
4076 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
4077 __ movsd(operand, ToDoubleRegister(instr->value()));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004078 } else {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004079 Register value(ToRegister(instr->value()));
4080 switch (elements_kind) {
4081 case EXTERNAL_PIXEL_ELEMENTS:
4082 case EXTERNAL_BYTE_ELEMENTS:
4083 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4084 __ movb(operand, value);
4085 break;
4086 case EXTERNAL_SHORT_ELEMENTS:
4087 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4088 __ movw(operand, value);
4089 break;
4090 case EXTERNAL_INT_ELEMENTS:
4091 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4092 __ movl(operand, value);
4093 break;
4094 case EXTERNAL_FLOAT_ELEMENTS:
4095 case EXTERNAL_DOUBLE_ELEMENTS:
4096 case FAST_ELEMENTS:
4097 case FAST_SMI_ELEMENTS:
4098 case FAST_DOUBLE_ELEMENTS:
4099 case FAST_HOLEY_ELEMENTS:
4100 case FAST_HOLEY_SMI_ELEMENTS:
4101 case FAST_HOLEY_DOUBLE_ELEMENTS:
4102 case DICTIONARY_ELEMENTS:
4103 case NON_STRICT_ARGUMENTS_ELEMENTS:
4104 UNREACHABLE();
4105 break;
4106 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004107 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004108}
4109
4110
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004111void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004112 XMMRegister value = ToDoubleRegister(instr->value());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004113 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004114 if (!key->IsConstantOperand()) {
4115 Register key_reg = ToRegister(key);
4116 // Even though the HLoad/StoreKeyedFastElement instructions force
4117 // the input representation for the key to be an integer, the
4118 // input gets replaced during bound check elimination with the index
4119 // argument to the bounds check, which can be tagged, so that case
4120 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004121 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004122 // Sign extend key because it could be a 32 bit negative value
4123 // and the dehoisted address computation happens in 64 bits
4124 __ movsxlq(key_reg, key_reg);
4125 }
4126 }
4127
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004128 if (instr->NeedsCanonicalization()) {
4129 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004130
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004131 __ ucomisd(value, value);
4132 __ j(parity_odd, &have_value); // NaN.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004133
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004134 __ Set(kScratchRegister, BitCast<uint64_t>(
4135 FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
4136 __ movq(value, kScratchRegister);
4137
4138 __ bind(&have_value);
4139 }
4140
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004141 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004142 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004143 key,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004144 FAST_DOUBLE_ELEMENTS,
4145 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4146 instr->additional_index());
4147
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004148 __ movsd(double_store_operand, value);
4149}
4150
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004151
4152void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004153 Register elements = ToRegister(instr->elements());
4154 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004155 if (!key->IsConstantOperand()) {
4156 Register key_reg = ToRegister(key);
4157 // Even though the HLoad/StoreKeyedFastElement instructions force
4158 // the input representation for the key to be an integer, the
4159 // input gets replaced during bound check elimination with the index
4160 // argument to the bounds check, which can be tagged, so that case
4161 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004162 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004163 // Sign extend key because it could be a 32 bit negative value
4164 // and the dehoisted address computation happens in 64 bits
4165 __ movsxlq(key_reg, key_reg);
4166 }
4167 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004168
4169 Operand operand =
4170 BuildFastArrayOperand(instr->elements(),
4171 key,
4172 FAST_ELEMENTS,
4173 FixedArray::kHeaderSize - kHeapObjectTag,
4174 instr->additional_index());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004175 if (instr->value()->IsRegister()) {
4176 __ movq(operand, ToRegister(instr->value()));
4177 } else {
4178 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4179 if (IsInteger32Constant(operand_value)) {
4180 Smi* smi_value = Smi::FromInt(ToInteger32(operand_value));
4181 __ Move(operand, smi_value);
4182 } else {
4183 Handle<Object> handle_value = ToHandle(operand_value);
4184 __ Move(operand, handle_value);
4185 }
4186 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004187
4188 if (instr->hydrogen()->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004189 ASSERT(instr->value()->IsRegister());
4190 Register value = ToRegister(instr->value());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004191 ASSERT(!instr->key()->IsConstantOperand());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004192 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004193 instr->hydrogen()->value()->IsHeapObject()
4194 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004195 // Compute address of modified element and store it into key register.
4196 Register key_reg(ToRegister(key));
4197 __ lea(key_reg, operand);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004198 __ RecordWrite(elements,
4199 key_reg,
4200 value,
4201 kSaveFPRegs,
4202 EMIT_REMEMBERED_SET,
4203 check_needed);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004204 }
4205}
4206
4207
4208void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4209 if (instr->is_external()) {
4210 DoStoreKeyedExternalArray(instr);
4211 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4212 DoStoreKeyedFixedDoubleArray(instr);
4213 } else {
4214 DoStoreKeyedFixedArray(instr);
4215 }
4216}
4217
4218
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004219void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004220 ASSERT(ToRegister(instr->object()).is(rdx));
4221 ASSERT(ToRegister(instr->key()).is(rcx));
4222 ASSERT(ToRegister(instr->value()).is(rax));
4223
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004224 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004225 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4226 : isolate()->builtins()->KeyedStoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004227 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4228}
4229
4230
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004231void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4232 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004233
4234 Handle<Map> from_map = instr->original_map();
4235 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004236 ElementsKind from_kind = instr->from_kind();
4237 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004238
4239 Label not_applicable;
4240 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
4241 __ j(not_equal, &not_applicable);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004242 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004243 Register new_map_reg = ToRegister(instr->new_map_temp());
4244 __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004245 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
4246 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004247 ASSERT_NE(instr->temp(), NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004248 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004249 ToRegister(instr->temp()), kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004250 } else {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004251 PushSafepointRegistersScope scope(this);
4252 if (!object_reg.is(rax)) {
4253 __ movq(rax, object_reg);
4254 }
4255 __ Move(rbx, to_map);
4256 TransitionElementsKindStub stub(from_kind, to_kind);
4257 __ CallStub(&stub);
4258 RecordSafepointWithRegisters(
4259 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004260 }
4261 __ bind(&not_applicable);
4262}
4263
4264
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004265void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4266 Register object = ToRegister(instr->object());
4267 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004268 Label no_memento_found;
4269 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004270 DeoptimizeIf(equal, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004271 __ bind(&no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004272}
4273
4274
danno@chromium.org160a7b02011-04-18 15:51:38 +00004275void LCodeGen::DoStringAdd(LStringAdd* instr) {
4276 EmitPushTaggedOperand(instr->left());
4277 EmitPushTaggedOperand(instr->right());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004278 StringAddStub stub(instr->hydrogen()->flags());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004279 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004280}
4281
4282
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004283void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004284 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004285 public:
4286 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4287 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004288 virtual void Generate() V8_OVERRIDE {
4289 codegen()->DoDeferredStringCharCodeAt(instr_);
4290 }
4291 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004292 private:
4293 LStringCharCodeAt* instr_;
4294 };
4295
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004296 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004297 new(zone()) DeferredStringCharCodeAt(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004298
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004299 StringCharLoadGenerator::Generate(masm(),
4300 ToRegister(instr->string()),
4301 ToRegister(instr->index()),
4302 ToRegister(instr->result()),
4303 deferred->entry());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004304 __ bind(deferred->exit());
4305}
4306
4307
4308void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4309 Register string = ToRegister(instr->string());
4310 Register result = ToRegister(instr->result());
4311
4312 // TODO(3095996): Get rid of this. For now, we need to make the
4313 // result register contain a valid pointer because it is already
4314 // contained in the register pointer map.
4315 __ Set(result, 0);
4316
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004317 PushSafepointRegistersScope scope(this);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004318 __ push(string);
4319 // Push the index as a smi. This is safe because of the checks in
4320 // DoStringCharCodeAt above.
4321 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4322 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004323 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004324 __ Push(Smi::FromInt(const_index));
4325 } else {
4326 Register index = ToRegister(instr->index());
4327 __ Integer32ToSmi(index, index);
4328 __ push(index);
4329 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004330 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004331 __ AssertSmi(rax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004332 __ SmiToInteger32(rax, rax);
4333 __ StoreToSafepointRegisterSlot(result, rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004334}
4335
4336
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004337void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004338 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004339 public:
4340 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4341 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004342 virtual void Generate() V8_OVERRIDE {
4343 codegen()->DoDeferredStringCharFromCode(instr_);
4344 }
4345 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004346 private:
4347 LStringCharFromCode* instr_;
4348 };
4349
4350 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004351 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004352
4353 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4354 Register char_code = ToRegister(instr->char_code());
4355 Register result = ToRegister(instr->result());
4356 ASSERT(!char_code.is(result));
4357
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004358 __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004359 __ j(above, deferred->entry());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004360 __ movsxlq(char_code, char_code);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004361 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4362 __ movq(result, FieldOperand(result,
4363 char_code, times_pointer_size,
4364 FixedArray::kHeaderSize));
4365 __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
4366 __ j(equal, deferred->entry());
4367 __ bind(deferred->exit());
4368}
4369
4370
4371void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4372 Register char_code = ToRegister(instr->char_code());
4373 Register result = ToRegister(instr->result());
4374
4375 // TODO(3095996): Get rid of this. For now, we need to make the
4376 // result register contain a valid pointer because it is already
4377 // contained in the register pointer map.
4378 __ Set(result, 0);
4379
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004380 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004381 __ Integer32ToSmi(char_code, char_code);
4382 __ push(char_code);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004383 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004384 __ StoreToSafepointRegisterSlot(result, rax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004385}
4386
4387
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004388void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004389 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004390 ASSERT(input->IsRegister() || input->IsStackSlot());
4391 LOperand* output = instr->result();
4392 ASSERT(output->IsDoubleRegister());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004393 if (input->IsRegister()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004394 __ Cvtlsi2sd(ToDoubleRegister(output), ToRegister(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004395 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004396 __ Cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004397 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004398}
4399
4400
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004401void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4402 LOperand* input = instr->value();
4403 ASSERT(input->IsRegister());
4404 LOperand* output = instr->result();
4405 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4406 if (!instr->hydrogen()->value()->HasRange() ||
4407 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4408 DeoptimizeIf(overflow, instr->environment());
4409 }
4410}
4411
4412
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004413void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004414 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004415 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004416 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004417
4418 __ LoadUint32(ToDoubleRegister(output),
4419 ToRegister(input),
4420 ToDoubleRegister(temp));
4421}
4422
4423
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00004424void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4425 LOperand* input = instr->value();
4426 ASSERT(input->IsRegister());
4427 LOperand* output = instr->result();
4428 if (!instr->hydrogen()->value()->HasRange() ||
4429 !instr->hydrogen()->value()->range()->IsInSmiRange() ||
4430 instr->hydrogen()->value()->range()->upper() == kMaxInt) {
4431 // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
4432 // interval, so we treat kMaxInt as a sentinel for this entire interval.
4433 __ testl(ToRegister(input), Immediate(0x80000000));
4434 DeoptimizeIf(not_zero, instr->environment());
4435 }
4436 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4437}
4438
4439
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004440void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004441 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004442 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4443 Register reg = ToRegister(input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004444
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004445 __ Integer32ToSmi(reg, reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004446}
4447
4448
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004449void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004450 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004451 public:
4452 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4453 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004454 virtual void Generate() V8_OVERRIDE {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004455 codegen()->DoDeferredNumberTagU(instr_);
4456 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004457 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004458 private:
4459 LNumberTagU* instr_;
4460 };
4461
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004462 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004463 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4464 Register reg = ToRegister(input);
4465
4466 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4467 __ cmpl(reg, Immediate(Smi::kMaxValue));
4468 __ j(above, deferred->entry());
4469 __ Integer32ToSmi(reg, reg);
4470 __ bind(deferred->exit());
4471}
4472
4473
4474void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) {
4475 Label slow;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004476 Register reg = ToRegister(instr->value());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004477 Register tmp = reg.is(rax) ? rcx : rax;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004478 XMMRegister temp_xmm = ToDoubleRegister(instr->temp());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004479
4480 // Preserve the value of all registers.
4481 PushSafepointRegistersScope scope(this);
4482
4483 Label done;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004484 // Load value into temp_xmm which will be preserved across potential call to
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004485 // runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable
4486 // XMM registers on x64).
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004487 XMMRegister xmm_scratch = double_scratch0();
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004488 __ LoadUint32(temp_xmm, reg, xmm_scratch);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004489
4490 if (FLAG_inline_new) {
4491 __ AllocateHeapNumber(reg, tmp, &slow);
4492 __ jmp(&done, Label::kNear);
4493 }
4494
4495 // Slow case: Call the runtime system to do the number allocation.
4496 __ bind(&slow);
4497
4498 // Put a valid pointer value in the stack slot where the result
4499 // register is stored, as this register is in the pointer map, but contains an
4500 // integer value.
4501 __ StoreToSafepointRegisterSlot(reg, Immediate(0));
4502
4503 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
4504 if (!reg.is(rax)) __ movq(reg, rax);
4505
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004506 // Done. Put the value in temp_xmm into the value of the allocated heap
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004507 // number.
4508 __ bind(&done);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004509 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004510 __ StoreToSafepointRegisterSlot(reg, reg);
4511}
4512
4513
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004514void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004515 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004516 public:
4517 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4518 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004519 virtual void Generate() V8_OVERRIDE {
4520 codegen()->DoDeferredNumberTagD(instr_);
4521 }
4522 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004523 private:
4524 LNumberTagD* instr_;
4525 };
4526
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004527 XMMRegister input_reg = ToDoubleRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004528 Register reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004529 Register tmp = ToRegister(instr->temp());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004530
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004531 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004532 if (FLAG_inline_new) {
4533 __ AllocateHeapNumber(reg, tmp, deferred->entry());
4534 } else {
4535 __ jmp(deferred->entry());
4536 }
4537 __ bind(deferred->exit());
4538 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004539}
4540
4541
4542void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004543 // TODO(3095996): Get rid of this. For now, we need to make the
4544 // result register contain a valid pointer because it is already
4545 // contained in the register pointer map.
4546 Register reg = ToRegister(instr->result());
4547 __ Move(reg, Smi::FromInt(0));
4548
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004549 {
4550 PushSafepointRegistersScope scope(this);
4551 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
4552 // Ensure that value in rax survives popping registers.
4553 __ movq(kScratchRegister, rax);
4554 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004555 __ movq(reg, kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004556}
4557
4558
4559void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004560 ASSERT(instr->value()->Equals(instr->result()));
4561 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004562 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4563 __ Integer32ToSmi(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004564}
4565
4566
4567void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004568 ASSERT(instr->value()->Equals(instr->result()));
4569 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004570 if (instr->needs_check()) {
4571 Condition is_smi = __ CheckSmi(input);
4572 DeoptimizeIf(NegateCondition(is_smi), instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004573 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004574 __ AssertSmi(input);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004575 }
4576 __ SmiToInteger32(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004577}
4578
4579
4580void LCodeGen::EmitNumberUntagD(Register input_reg,
4581 XMMRegister result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004582 bool can_convert_undefined_to_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004583 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004584 LEnvironment* env,
4585 NumberUntagDMode mode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004586 Label convert, load_smi, done;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004587
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004588 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004589 // Smi check.
4590 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004591
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004592 // Heap number map check.
4593 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4594 Heap::kHeapNumberMapRootIndex);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00004595
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004596 // On x64 it is safe to load at heap number offset before evaluating the map
4597 // check, since all heap objects are at least two words long.
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004598 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004599
4600 if (can_convert_undefined_to_nan) {
4601 __ j(not_equal, &convert);
4602 } else {
4603 DeoptimizeIf(not_equal, env);
4604 }
4605
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004606 if (deoptimize_on_minus_zero) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004607 XMMRegister xmm_scratch = double_scratch0();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004608 __ xorps(xmm_scratch, xmm_scratch);
4609 __ ucomisd(xmm_scratch, result_reg);
4610 __ j(not_equal, &done, Label::kNear);
4611 __ movmskpd(kScratchRegister, result_reg);
4612 __ testq(kScratchRegister, Immediate(1));
4613 DeoptimizeIf(not_zero, env);
4614 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004615 __ jmp(&done, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004616
4617 if (can_convert_undefined_to_nan) {
4618 __ bind(&convert);
4619
4620 // Convert undefined (and hole) to NaN. Compute NaN as 0/0.
4621 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
4622 DeoptimizeIf(not_equal, env);
4623
4624 __ xorps(result_reg, result_reg);
4625 __ divsd(result_reg, result_reg);
4626 __ jmp(&done, Label::kNear);
4627 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004628 } else {
4629 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004630 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004631
4632 // Smi to XMM conversion
4633 __ bind(&load_smi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004634 __ SmiToInteger32(kScratchRegister, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004635 __ Cvtlsi2sd(result_reg, kScratchRegister);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004636 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004637}
4638
4639
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004640void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004641 Register input_reg = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004642
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004643 if (instr->truncating()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004644 Label no_heap_number, check_bools, check_false;
4645
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004646 // Heap number map check.
4647 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4648 Heap::kHeapNumberMapRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004649 __ j(not_equal, &no_heap_number, Label::kNear);
4650 __ TruncateHeapNumberToI(input_reg, input_reg);
4651 __ jmp(done);
4652
4653 __ bind(&no_heap_number);
4654 // Check for Oddballs. Undefined/False is converted to zero and True to one
4655 // for truncating conversions.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004656 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004657 __ j(not_equal, &check_bools, Label::kNear);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004658 __ Set(input_reg, 0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004659 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004660
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004661 __ bind(&check_bools);
4662 __ CompareRoot(input_reg, Heap::kTrueValueRootIndex);
4663 __ j(not_equal, &check_false, Label::kNear);
4664 __ Set(input_reg, 1);
4665 __ jmp(done);
4666
4667 __ bind(&check_false);
4668 __ CompareRoot(input_reg, Heap::kFalseValueRootIndex);
4669 __ RecordComment("Deferred TaggedToI: cannot truncate");
4670 DeoptimizeIf(not_equal, instr->environment());
4671 __ Set(input_reg, 0);
4672 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004673 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004674 Label bailout;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004675 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004676 __ TaggedToI(input_reg, input_reg, xmm_temp,
4677 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4678
4679 __ jmp(done);
4680 __ bind(&bailout);
4681 DeoptimizeIf(no_condition, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004682 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004683}
4684
4685
4686void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004687 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004688 public:
4689 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4690 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004691 virtual void Generate() V8_OVERRIDE {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004692 codegen()->DoDeferredTaggedToI(instr_, done());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004693 }
4694 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004695 private:
4696 LTaggedToI* instr_;
4697 };
4698
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004699 LOperand* input = instr->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004700 ASSERT(input->IsRegister());
4701 ASSERT(input->Equals(instr->result()));
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004702 Register input_reg = ToRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004703
4704 if (instr->hydrogen()->value()->representation().IsSmi()) {
4705 __ SmiToInteger32(input_reg, input_reg);
4706 } else {
4707 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
4708 __ JumpIfNotSmi(input_reg, deferred->entry());
4709 __ SmiToInteger32(input_reg, input_reg);
4710 __ bind(deferred->exit());
4711 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004712}
4713
4714
4715void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004716 LOperand* input = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004717 ASSERT(input->IsRegister());
4718 LOperand* result = instr->result();
4719 ASSERT(result->IsDoubleRegister());
4720
4721 Register input_reg = ToRegister(input);
4722 XMMRegister result_reg = ToDoubleRegister(result);
4723
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004724 HValue* value = instr->hydrogen()->value();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004725 NumberUntagDMode mode = value->representation().IsSmi()
4726 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004727
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004728 EmitNumberUntagD(input_reg, result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004729 instr->hydrogen()->can_convert_undefined_to_nan(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004730 instr->hydrogen()->deoptimize_on_minus_zero(),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004731 instr->environment(),
4732 mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004733}
4734
4735
4736void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004737 LOperand* input = instr->value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004738 ASSERT(input->IsDoubleRegister());
4739 LOperand* result = instr->result();
4740 ASSERT(result->IsRegister());
4741
4742 XMMRegister input_reg = ToDoubleRegister(input);
4743 Register result_reg = ToRegister(result);
4744
4745 if (instr->truncating()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004746 __ TruncateDoubleToI(result_reg, input_reg);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004747 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004748 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004749 XMMRegister xmm_scratch = double_scratch0();
4750 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004751 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4752
4753 __ jmp(&done, Label::kNear);
4754 __ bind(&bailout);
4755 DeoptimizeIf(no_condition, instr->environment());
4756 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004757 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004758}
4759
4760
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004761void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4762 LOperand* input = instr->value();
4763 ASSERT(input->IsDoubleRegister());
4764 LOperand* result = instr->result();
4765 ASSERT(result->IsRegister());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004766
4767 XMMRegister input_reg = ToDoubleRegister(input);
4768 Register result_reg = ToRegister(result);
4769
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004770 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004771 XMMRegister xmm_scratch = double_scratch0();
4772 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004773 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004774
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004775 __ jmp(&done, Label::kNear);
4776 __ bind(&bailout);
4777 DeoptimizeIf(no_condition, instr->environment());
4778 __ bind(&done);
4779
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004780 __ Integer32ToSmi(result_reg, result_reg);
4781 DeoptimizeIf(overflow, instr->environment());
4782}
4783
4784
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004785void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004786 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004787 Condition cc = masm()->CheckSmi(ToRegister(input));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004788 DeoptimizeIf(NegateCondition(cc), instr->environment());
4789}
4790
4791
4792void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004793 if (!instr->hydrogen()->value()->IsHeapObject()) {
4794 LOperand* input = instr->value();
4795 Condition cc = masm()->CheckSmi(ToRegister(input));
4796 DeoptimizeIf(cc, instr->environment());
4797 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004798}
4799
4800
4801void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004802 Register input = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004803
4804 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
4805
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004806 if (instr->hydrogen()->is_interval_check()) {
4807 InstanceType first;
4808 InstanceType last;
4809 instr->hydrogen()->GetCheckInterval(&first, &last);
4810
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004811 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4812 Immediate(static_cast<int8_t>(first)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004813
4814 // If there is only one type in the interval check for equality.
4815 if (first == last) {
4816 DeoptimizeIf(not_equal, instr->environment());
4817 } else {
4818 DeoptimizeIf(below, instr->environment());
4819 // Omit check for the last type.
4820 if (last != LAST_TYPE) {
4821 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4822 Immediate(static_cast<int8_t>(last)));
4823 DeoptimizeIf(above, instr->environment());
4824 }
4825 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004826 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004827 uint8_t mask;
4828 uint8_t tag;
4829 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4830
4831 if (IsPowerOf2(mask)) {
4832 ASSERT(tag == 0 || IsPowerOf2(tag));
4833 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4834 Immediate(mask));
4835 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4836 } else {
4837 __ movzxbl(kScratchRegister,
4838 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
4839 __ andb(kScratchRegister, Immediate(mask));
4840 __ cmpb(kScratchRegister, Immediate(tag));
4841 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004842 }
4843 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004844}
4845
4846
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004847void LCodeGen::DoCheckValue(LCheckValue* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004848 Register reg = ToRegister(instr->value());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004849 __ Cmp(reg, instr->hydrogen()->object().handle());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004850 DeoptimizeIf(not_equal, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004851}
4852
4853
danno@chromium.org59400602013-08-13 17:09:37 +00004854void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
4855 {
4856 PushSafepointRegistersScope scope(this);
4857 __ push(object);
4858 CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr);
4859 __ testq(rax, Immediate(kSmiTagMask));
4860 }
4861 DeoptimizeIf(zero, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004862}
4863
4864
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004865void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004866 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00004867 public:
4868 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
4869 : LDeferredCode(codegen), instr_(instr), object_(object) {
4870 SetExit(check_maps());
4871 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004872 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00004873 codegen()->DoDeferredInstanceMigration(instr_, object_);
4874 }
4875 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004876 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00004877 private:
4878 LCheckMaps* instr_;
4879 Label check_maps_;
4880 Register object_;
4881 };
4882
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00004883 if (instr->hydrogen()->CanOmitMapChecks()) return;
danno@chromium.org59400602013-08-13 17:09:37 +00004884
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004885 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004886 ASSERT(input->IsRegister());
4887 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004888
danno@chromium.org59400602013-08-13 17:09:37 +00004889 DeferredCheckMaps* deferred = NULL;
4890 if (instr->hydrogen()->has_migration_target()) {
4891 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
4892 __ bind(deferred->check_maps());
4893 }
4894
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004895 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00004896 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004897 for (int i = 0; i < map_set.size() - 1; i++) {
4898 Handle<Map> map = map_set.at(i).handle();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004899 __ CompareMap(reg, map, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004900 __ j(equal, &success);
4901 }
danno@chromium.org59400602013-08-13 17:09:37 +00004902
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004903 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
danno@chromium.org59400602013-08-13 17:09:37 +00004904 __ CompareMap(reg, map, &success);
4905 if (instr->hydrogen()->has_migration_target()) {
4906 __ j(not_equal, deferred->entry());
4907 } else {
4908 DeoptimizeIf(not_equal, instr->environment());
4909 }
4910
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004911 __ bind(&success);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004912}
4913
4914
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004915void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4916 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004917 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004918 Register result_reg = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004919 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004920}
4921
4922
4923void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4924 ASSERT(instr->unclamped()->Equals(instr->result()));
4925 Register value_reg = ToRegister(instr->result());
4926 __ ClampUint8(value_reg);
4927}
4928
4929
4930void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4931 ASSERT(instr->unclamped()->Equals(instr->result()));
4932 Register input_reg = ToRegister(instr->unclamped());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004933 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004934 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004935 Label is_smi, done, heap_number;
4936
4937 __ JumpIfSmi(input_reg, &is_smi);
4938
4939 // Check for heap number
4940 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
4941 factory()->heap_number_map());
4942 __ j(equal, &heap_number, Label::kNear);
4943
4944 // Check for undefined. Undefined is converted to zero for clamping
4945 // conversions.
4946 __ Cmp(input_reg, factory()->undefined_value());
4947 DeoptimizeIf(not_equal, instr->environment());
4948 __ movq(input_reg, Immediate(0));
4949 __ jmp(&done, Label::kNear);
4950
4951 // Heap number
4952 __ bind(&heap_number);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004953 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
4954 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004955 __ jmp(&done, Label::kNear);
4956
4957 // smi
4958 __ bind(&is_smi);
4959 __ SmiToInteger32(input_reg, input_reg);
4960 __ ClampUint8(input_reg);
4961
4962 __ bind(&done);
4963}
4964
4965
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004966void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004967 class DeferredAllocate V8_FINAL : public LDeferredCode {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004968 public:
4969 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
4970 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004971 virtual void Generate() V8_OVERRIDE {
4972 codegen()->DoDeferredAllocate(instr_);
4973 }
4974 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004975 private:
4976 LAllocate* instr_;
4977 };
4978
4979 DeferredAllocate* deferred =
4980 new(zone()) DeferredAllocate(this, instr);
4981
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004982 Register result = ToRegister(instr->result());
4983 Register temp = ToRegister(instr->temp());
4984
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004985 // Allocate memory for the object.
4986 AllocationFlags flags = TAG_OBJECT;
4987 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
4988 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
4989 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004990 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
4991 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
4992 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004993 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004994 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
4995 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004996 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004997 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004998
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004999 if (instr->size()->IsConstantOperand()) {
5000 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005001 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005002 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005003 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005004 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005005 }
5006
5007 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005008
5009 if (instr->hydrogen()->MustPrefillWithFiller()) {
5010 if (instr->size()->IsConstantOperand()) {
5011 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5012 __ movl(temp, Immediate((size / kPointerSize) - 1));
5013 } else {
5014 temp = ToRegister(instr->size());
5015 __ sar(temp, Immediate(kPointerSizeLog2));
5016 __ decl(temp);
5017 }
5018 Label loop;
5019 __ bind(&loop);
5020 __ Move(FieldOperand(result, temp, times_pointer_size, 0),
5021 isolate()->factory()->one_pointer_filler_map());
5022 __ decl(temp);
5023 __ j(not_zero, &loop);
5024 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005025}
5026
5027
5028void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005029 Register result = ToRegister(instr->result());
5030
5031 // TODO(3095996): Get rid of this. For now, we need to make the
5032 // result register contain a valid pointer because it is already
5033 // contained in the register pointer map.
danno@chromium.orgf005df62013-04-30 16:36:45 +00005034 __ Move(result, Smi::FromInt(0));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005035
5036 PushSafepointRegistersScope scope(this);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005037 if (instr->size()->IsRegister()) {
5038 Register size = ToRegister(instr->size());
5039 ASSERT(!size.is(result));
5040 __ Integer32ToSmi(size, size);
5041 __ push(size);
5042 } else {
5043 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5044 __ Push(Smi::FromInt(size));
5045 }
5046
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005047 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5048 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5049 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005050 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005051 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5052 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005053 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005054 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005055 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005056 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005057 __ StoreToSafepointRegisterSlot(result, rax);
5058}
5059
5060
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005062 ASSERT(ToRegister(instr->value()).is(rax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063 __ push(rax);
5064 CallRuntime(Runtime::kToFastProperties, 1, instr);
5065}
5066
5067
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005068void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005069 Label materialized;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005070 // Registers will be used as follows:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005071 // rcx = literals array.
5072 // rbx = regexp literal.
5073 // rax = regexp literal clone.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005074 int literal_offset =
5075 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005076 __ Move(rcx, instr->hydrogen()->literals());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005077 __ movq(rbx, FieldOperand(rcx, literal_offset));
5078 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005079 __ j(not_equal, &materialized, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005080
5081 // Create regexp literal using runtime function
5082 // Result will be in rax.
5083 __ push(rcx);
5084 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
5085 __ Push(instr->hydrogen()->pattern());
5086 __ Push(instr->hydrogen()->flags());
5087 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5088 __ movq(rbx, rax);
5089
5090 __ bind(&materialized);
5091 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5092 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005093 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005094 __ jmp(&allocated);
5095
5096 __ bind(&runtime_allocate);
5097 __ push(rbx);
5098 __ Push(Smi::FromInt(size));
5099 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5100 __ pop(rbx);
5101
5102 __ bind(&allocated);
5103 // Copy the content into the newly allocated memory.
5104 // (Unroll copy loop once for better throughput).
5105 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5106 __ movq(rdx, FieldOperand(rbx, i));
5107 __ movq(rcx, FieldOperand(rbx, i + kPointerSize));
5108 __ movq(FieldOperand(rax, i), rdx);
5109 __ movq(FieldOperand(rax, i + kPointerSize), rcx);
5110 }
5111 if ((size % (2 * kPointerSize)) != 0) {
5112 __ movq(rdx, FieldOperand(rbx, size - kPointerSize));
5113 __ movq(FieldOperand(rax, size - kPointerSize), rdx);
5114 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005115}
5116
5117
5118void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005119 // Use the fast case closure allocation code that allocates in new
5120 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005121 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005122 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5123 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5124 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005125 __ Move(rbx, instr->hydrogen()->shared_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005126 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005127 } else {
5128 __ push(rsi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005129 __ Push(instr->hydrogen()->shared_info());
5130 __ PushRoot(pretenure ? Heap::kTrueValueRootIndex :
5131 Heap::kFalseValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005132 CallRuntime(Runtime::kNewClosure, 3, instr);
5133 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005134}
5135
5136
5137void LCodeGen::DoTypeof(LTypeof* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005138 LOperand* input = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00005139 EmitPushTaggedOperand(input);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005140 CallRuntime(Runtime::kTypeof, 1, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005141}
5142
5143
danno@chromium.org160a7b02011-04-18 15:51:38 +00005144void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
5145 ASSERT(!operand->IsDoubleRegister());
5146 if (operand->IsConstantOperand()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005147 __ Push(ToHandle(LConstantOperand::cast(operand)));
danno@chromium.org160a7b02011-04-18 15:51:38 +00005148 } else if (operand->IsRegister()) {
5149 __ push(ToRegister(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005150 } else {
danno@chromium.org160a7b02011-04-18 15:51:38 +00005151 __ push(ToOperand(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005152 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005153}
5154
5155
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005156void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005157 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005158
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005159 Condition final_branch_condition =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005160 EmitTypeofIs(instr->TrueLabel(chunk_),
5161 instr->FalseLabel(chunk_), input, instr->type_literal());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005162 if (final_branch_condition != no_condition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005163 EmitBranch(instr, final_branch_condition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005164 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005165}
5166
5167
5168Condition LCodeGen::EmitTypeofIs(Label* true_label,
5169 Label* false_label,
5170 Register input,
5171 Handle<String> type_name) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005172 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005173 if (type_name->Equals(heap()->number_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005174 __ JumpIfSmi(input, true_label);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00005175 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
5176 Heap::kHeapNumberMapRootIndex);
5177
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005178 final_branch_condition = equal;
5179
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005180 } else if (type_name->Equals(heap()->string_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005181 __ JumpIfSmi(input, false_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005182 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
5183 __ j(above_equal, false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005184 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5185 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005186 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005187
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005188 } else if (type_name->Equals(heap()->symbol_string())) {
5189 __ JumpIfSmi(input, false_label);
5190 __ CmpObjectType(input, SYMBOL_TYPE, input);
5191 final_branch_condition = equal;
5192
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005193 } else if (type_name->Equals(heap()->boolean_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005194 __ CompareRoot(input, Heap::kTrueValueRootIndex);
5195 __ j(equal, true_label);
5196 __ CompareRoot(input, Heap::kFalseValueRootIndex);
5197 final_branch_condition = equal;
5198
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005199 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005200 __ CompareRoot(input, Heap::kNullValueRootIndex);
5201 final_branch_condition = equal;
5202
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005203 } else if (type_name->Equals(heap()->undefined_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005204 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
5205 __ j(equal, true_label);
5206 __ JumpIfSmi(input, false_label);
5207 // Check for undetectable objects => true.
5208 __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
5209 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5210 Immediate(1 << Map::kIsUndetectable));
5211 final_branch_condition = not_zero;
5212
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005213 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005214 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005215 __ JumpIfSmi(input, false_label);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005216 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
5217 __ j(equal, true_label);
5218 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5219 final_branch_condition = equal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005220
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005221 } else if (type_name->Equals(heap()->object_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005222 __ JumpIfSmi(input, false_label);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005223 if (!FLAG_harmony_typeof) {
5224 __ CompareRoot(input, Heap::kNullValueRootIndex);
5225 __ j(equal, true_label);
5226 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005227 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005228 __ j(below, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005229 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
5230 __ j(above, false_label);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005231 // Check for undetectable objects => false.
5232 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5233 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005234 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005235
5236 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005237 __ jmp(false_label);
5238 }
5239
5240 return final_branch_condition;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005241}
5242
5243
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005244void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005245 Register temp = ToRegister(instr->temp());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005246
5247 EmitIsConstructCall(temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005248 EmitBranch(instr, equal);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005249}
5250
5251
5252void LCodeGen::EmitIsConstructCall(Register temp) {
5253 // Get the frame pointer for the calling frame.
5254 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
5255
5256 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005257 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005258 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5259 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005260 __ j(not_equal, &check_frame_marker, Label::kNear);
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005261 __ movq(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005262
5263 // Check the marker in the calling frame.
5264 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005265 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5266 Smi::FromInt(StackFrame::CONSTRUCT));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005267}
5268
5269
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005270void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005271 if (info()->IsStub()) return;
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005272 // Ensure that we have enough space after the previous lazy-bailout
5273 // instruction for patching the code here.
5274 int current_pc = masm()->pc_offset();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005275 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5276 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5277 __ Nop(padding_size);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005278 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005279}
5280
5281
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005282void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005283 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5284 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005285 ASSERT(instr->HasEnvironment());
5286 LEnvironment* env = instr->environment();
5287 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5288 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005289}
5290
5291
5292void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005293 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5294 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5295 // needed return address), even though the implementation of LAZY and EAGER is
5296 // now identical. When LAZY is eventually completely folded into EAGER, remove
5297 // the special case below.
5298 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5299 type = Deoptimizer::LAZY;
danno@chromium.orgaefd6072013-05-14 14:11:47 +00005300 }
danno@chromium.org59400602013-08-13 17:09:37 +00005301
5302 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005303 DeoptimizeIf(no_condition, instr->environment(), type);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005304}
5305
5306
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005307void LCodeGen::DoDummyUse(LDummyUse* instr) {
5308 // Nothing to see here, move on!
5309}
5310
5311
ager@chromium.org04921a82011-06-27 13:21:41 +00005312void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005313 PushSafepointRegistersScope scope(this);
5314 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
5315 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5316 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
5317 ASSERT(instr->HasEnvironment());
5318 LEnvironment* env = instr->environment();
5319 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005320}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005321
ager@chromium.org04921a82011-06-27 13:21:41 +00005322
5323void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005324 class DeferredStackCheck V8_FINAL : public LDeferredCode {
ager@chromium.org04921a82011-06-27 13:21:41 +00005325 public:
5326 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5327 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005328 virtual void Generate() V8_OVERRIDE {
5329 codegen()->DoDeferredStackCheck(instr_);
5330 }
5331 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005332 private:
5333 LStackCheck* instr_;
5334 };
5335
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005336 ASSERT(instr->HasEnvironment());
5337 LEnvironment* env = instr->environment();
5338 // There is no LLazyBailout instruction for stack-checks. We have to
5339 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005340 if (instr->hydrogen()->is_function_entry()) {
5341 // Perform stack overflow check.
5342 Label done;
5343 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5344 __ j(above_equal, &done, Label::kNear);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005345 CallCode(isolate()->builtins()->StackCheck(),
5346 RelocInfo::CODE_TARGET,
5347 instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005348 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5349 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00005350 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005351 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5352 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005353 } else {
5354 ASSERT(instr->hydrogen()->is_backwards_branch());
5355 // Perform stack overflow check if this goto needs it before jumping.
5356 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005357 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005358 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5359 __ j(below, deferred_stack_check->entry());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005360 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
5361 last_lazy_deopt_pc_ = masm()->pc_offset();
ager@chromium.org04921a82011-06-27 13:21:41 +00005362 __ bind(instr->done_label());
5363 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005364 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5365 // Don't record a deoptimization index for the safepoint here.
5366 // This will be done explicitly when emitting call and the safepoint in
5367 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005368 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005369}
5370
5371
5372void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005373 // This is a pseudo-instruction that ensures that the environment here is
5374 // properly registered for deoptimization and records the assembler's PC
5375 // offset.
5376 LEnvironment* environment = instr->environment();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005377
5378 // If the environment were already registered, we would have no way of
5379 // backpatching it with the spill slot operands.
5380 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005381 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005382
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005383 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005384}
5385
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005386
5387void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5388 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
5389 DeoptimizeIf(equal, instr->environment());
5390
5391 Register null_value = rdi;
5392 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5393 __ cmpq(rax, null_value);
5394 DeoptimizeIf(equal, instr->environment());
5395
5396 Condition cc = masm()->CheckSmi(rax);
5397 DeoptimizeIf(cc, instr->environment());
5398
5399 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5400 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
5401 DeoptimizeIf(below_equal, instr->environment());
5402
5403 Label use_cache, call_runtime;
5404 __ CheckEnumCache(null_value, &call_runtime);
5405
5406 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
5407 __ jmp(&use_cache, Label::kNear);
5408
5409 // Get the set of properties to enumerate.
5410 __ bind(&call_runtime);
5411 __ push(rax);
5412 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5413
5414 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
5415 Heap::kMetaMapRootIndex);
5416 DeoptimizeIf(not_equal, instr->environment());
5417 __ bind(&use_cache);
5418}
5419
5420
5421void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5422 Register map = ToRegister(instr->map());
5423 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005424 Label load_cache, done;
5425 __ EnumLength(result, map);
5426 __ Cmp(result, Smi::FromInt(0));
5427 __ j(not_equal, &load_cache);
5428 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex);
5429 __ jmp(&done);
5430 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005431 __ LoadInstanceDescriptors(map, result);
5432 __ movq(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005433 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005434 __ movq(result,
5435 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005436 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005437 Condition cc = masm()->CheckSmi(result);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005438 DeoptimizeIf(cc, instr->environment());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005439}
5440
5441
5442void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5443 Register object = ToRegister(instr->value());
5444 __ cmpq(ToRegister(instr->map()),
5445 FieldOperand(object, HeapObject::kMapOffset));
5446 DeoptimizeIf(not_equal, instr->environment());
5447}
5448
5449
5450void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5451 Register object = ToRegister(instr->object());
5452 Register index = ToRegister(instr->index());
5453
5454 Label out_of_object, done;
5455 __ SmiToInteger32(index, index);
5456 __ cmpl(index, Immediate(0));
5457 __ j(less, &out_of_object);
5458 __ movq(object, FieldOperand(object,
5459 index,
5460 times_pointer_size,
5461 JSObject::kHeaderSize));
5462 __ jmp(&done, Label::kNear);
5463
5464 __ bind(&out_of_object);
5465 __ movq(object, FieldOperand(object, JSObject::kPropertiesOffset));
5466 __ negl(index);
5467 // Index is now equal to out of object property index plus 1.
5468 __ movq(object, FieldOperand(object,
5469 index,
5470 times_pointer_size,
5471 FixedArray::kHeaderSize - kPointerSize));
5472 __ bind(&done);
5473}
5474
5475
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005476#undef __
5477
5478} } // namespace v8::internal
5479
5480#endif // V8_TARGET_ARCH_X64