blob: 4dc9d4a34a9f49c6bf7c41679f522a2e188cdd45 [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
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +000053 virtual void BeforeCall(int call_size) const V8_OVERRIDE {}
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +000054
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000055 virtual void AfterCall() const V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000056 codegen_->RecordSafepoint(pointers_, deopt_mode_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000057 }
58
59 private:
60 LCodeGen* codegen_;
61 LPointerMap* pointers_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +000062 Safepoint::DeoptMode deopt_mode_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000063};
64
65
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000066#define __ masm()->
67
68bool LCodeGen::GenerateCode() {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000069 LPhase phase("Z_Code generation", chunk());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000070 ASSERT(is_unused());
71 status_ = GENERATING;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000072
73 // Open a frame scope to indicate that there is a frame on the stack. The
74 // MANUAL indicates that the scope shouldn't actually generate code to set up
75 // the frame (that is done in GeneratePrologue).
76 FrameScope frame_scope(masm_, StackFrame::MANUAL);
77
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000078 return GeneratePrologue() &&
79 GenerateBody() &&
80 GenerateDeferredCode() &&
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000081 GenerateJumpTable() &&
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000082 GenerateSafepointTable();
83}
84
85
86void LCodeGen::FinishCode(Handle<Code> code) {
87 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000088 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000089 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +000090 if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000091 PopulateDeoptimizationData(code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000092 info()->CommitDependencies(code);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000093}
94
95
danno@chromium.org59400602013-08-13 17:09:37 +000096void LChunkBuilder::Abort(BailoutReason reason) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000097 info()->set_bailout_reason(reason);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000098 status_ = ABORTED;
99}
100
101
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000102#ifdef _MSC_VER
103void LCodeGen::MakeSureStackPagesMapped(int offset) {
104 const int kPageSize = 4 * KB;
105 for (offset -= kPageSize; offset > 0; offset -= kPageSize) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000106 __ movp(Operand(rsp, offset), rax);
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000107 }
108}
109#endif
110
111
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000112void LCodeGen::SaveCallerDoubles() {
113 ASSERT(info()->saves_caller_doubles());
114 ASSERT(NeedsEagerFrame());
115 Comment(";;; Save clobbered callee double registers");
116 int count = 0;
117 BitVector* doubles = chunk()->allocated_double_registers();
118 BitVector::Iterator save_iterator(doubles);
119 while (!save_iterator.Done()) {
120 __ movsd(MemOperand(rsp, count * kDoubleSize),
121 XMMRegister::FromAllocationIndex(save_iterator.Current()));
122 save_iterator.Advance();
123 count++;
124 }
125}
126
127
128void LCodeGen::RestoreCallerDoubles() {
129 ASSERT(info()->saves_caller_doubles());
130 ASSERT(NeedsEagerFrame());
131 Comment(";;; Restore clobbered callee double registers");
132 BitVector* doubles = chunk()->allocated_double_registers();
133 BitVector::Iterator save_iterator(doubles);
134 int count = 0;
135 while (!save_iterator.Done()) {
136 __ movsd(XMMRegister::FromAllocationIndex(save_iterator.Current()),
137 MemOperand(rsp, count * kDoubleSize));
138 save_iterator.Advance();
139 count++;
140 }
141}
142
143
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000144bool LCodeGen::GeneratePrologue() {
145 ASSERT(is_generating());
146
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000147 if (info()->IsOptimizing()) {
148 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000149
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000150#ifdef DEBUG
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000151 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000152 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000153 __ int3();
154 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000155#endif
156
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000157 // Classic mode functions need to replace the receiver with the global proxy
158 // when called as functions (without an explicit receiver object).
159 if (info_->this_has_uses() &&
160 info_->is_classic_mode() &&
161 !info_->is_native()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000162 Label ok;
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000163 StackArgumentsAccessor args(rsp, scope()->num_parameters());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000164 __ movp(rcx, args.GetReceiverOperand());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000165
166 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex);
167 __ j(not_equal, &ok, Label::kNear);
168
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000169 __ movp(rcx, GlobalObjectOperand());
170 __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000171
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000172 __ movp(args.GetReceiverOperand(), rcx);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000173
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000174 __ bind(&ok);
175 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000176 }
177
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000178 info()->set_prologue_offset(masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000179 if (NeedsEagerFrame()) {
180 ASSERT(!frame_is_built_);
181 frame_is_built_ = true;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000182 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000183 info()->AddNoFrameRange(0, masm_->pc_offset());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000184 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000185
186 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000187 int slots = GetStackSlotCount();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000188 if (slots > 0) {
189 if (FLAG_debug_code) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000190 __ subq(rsp, Immediate(slots * kPointerSize));
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000191#ifdef _MSC_VER
192 MakeSureStackPagesMapped(slots * kPointerSize);
193#endif
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000194 __ push(rax);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +0000195 __ Set(rax, slots);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000196 __ movq(kScratchRegister, kSlotsZapValue);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000197 Label loop;
198 __ bind(&loop);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000199 __ movp(MemOperand(rsp, rax, times_pointer_size, 0),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000200 kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000201 __ decl(rax);
202 __ j(not_zero, &loop);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000203 __ pop(rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000204 } else {
205 __ subq(rsp, Immediate(slots * kPointerSize));
206#ifdef _MSC_VER
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000207 MakeSureStackPagesMapped(slots * kPointerSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000208#endif
209 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000210
211 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000212 SaveCallerDoubles();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000213 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000214 }
215
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000216 // Possibly allocate a local context.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000217 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000218 if (heap_slots > 0) {
219 Comment(";;; Allocate local context");
220 // Argument to NewContext is the function, which is still in rdi.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000221 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
222 FastNewContextStub stub(heap_slots);
223 __ CallStub(&stub);
224 } else {
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000225 __ push(rdi);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000226 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000227 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000228 RecordSafepoint(Safepoint::kNoLazyDeopt);
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +0000229 // Context is returned in rax. It replaces the context passed to us.
230 // It's saved in the stack and kept live in rsi.
231 __ movp(rsi, rax);
232 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000233
234 // Copy any necessary parameters into the context.
235 int num_parameters = scope()->num_parameters();
236 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000237 Variable* var = scope()->parameter(i);
238 if (var->IsContextSlot()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000239 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
240 (num_parameters - 1 - i) * kPointerSize;
241 // Load parameter from stack.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000242 __ movp(rax, Operand(rbp, parameter_offset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000243 // Store it in the context.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000244 int context_offset = Context::SlotOffset(var->index());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000245 __ movp(Operand(rsi, context_offset), rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000246 // Update the write barrier. This clobbers rax and rbx.
247 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000248 }
249 }
250 Comment(";;; End allocate local context");
251 }
252
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000253 // Trace the call.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000254 if (FLAG_trace && info()->IsOptimizing()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000255 __ CallRuntime(Runtime::kTraceEnter, 0);
256 }
257 return !is_aborted();
258}
259
260
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000261void LCodeGen::GenerateOsrPrologue() {
262 // Generate the OSR entry prologue at the first unknown OSR value, or if there
263 // are none, at the OSR entrypoint instruction.
264 if (osr_pc_offset_ >= 0) return;
265
266 osr_pc_offset_ = masm()->pc_offset();
267
268 // Adjust the frame size, subsuming the unoptimized frame into the
269 // optimized frame.
270 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
271 ASSERT(slots >= 0);
272 __ subq(rsp, Immediate(slots * kPointerSize));
273}
274
275
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000276bool LCodeGen::GenerateJumpTable() {
danno@chromium.org169691d2013-07-15 08:01:13 +0000277 Label needs_frame;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000278 if (jump_table_.length() > 0) {
279 Comment(";;; -------------------- Jump table --------------------");
280 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000281 for (int i = 0; i < jump_table_.length(); i++) {
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000282 __ bind(&jump_table_[i].label);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000283 Address entry = jump_table_[i].address;
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000284 Deoptimizer::BailoutType type = jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000285 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000286 if (id == Deoptimizer::kNotDeoptimizationEntry) {
287 Comment(";;; jump table entry %d.", i);
288 } else {
289 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
290 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000291 if (jump_table_[i].needs_frame) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000292 ASSERT(!info()->saves_caller_doubles());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000293 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry));
danno@chromium.org169691d2013-07-15 08:01:13 +0000294 if (needs_frame.is_bound()) {
295 __ jmp(&needs_frame);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000296 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000297 __ bind(&needs_frame);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000298 __ movp(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset));
danno@chromium.org169691d2013-07-15 08:01:13 +0000299 __ push(rbp);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000300 __ movp(rbp, rsp);
danno@chromium.org169691d2013-07-15 08:01:13 +0000301 __ push(rsi);
302 // This variant of deopt can only be used with stubs. Since we don't
303 // have a function pointer to install in the stack frame that we're
304 // building, install a special marker there instead.
305 ASSERT(info()->IsStub());
306 __ Move(rsi, Smi::FromInt(StackFrame::STUB));
307 __ push(rsi);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000308 __ movp(rsi, MemOperand(rsp, kPointerSize));
danno@chromium.org169691d2013-07-15 08:01:13 +0000309 __ call(kScratchRegister);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000310 }
311 } else {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000312 if (info()->saves_caller_doubles()) {
313 ASSERT(info()->IsStub());
314 RestoreCallerDoubles();
315 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000316 __ call(entry, RelocInfo::RUNTIME_ENTRY);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000317 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000318 }
319 return !is_aborted();
320}
321
322
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000323bool LCodeGen::GenerateDeferredCode() {
324 ASSERT(is_generating());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000325 if (deferred_.length() > 0) {
326 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
327 LDeferredCode* code = deferred_[i];
danno@chromium.org59400602013-08-13 17:09:37 +0000328
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000329 HValue* value =
330 instructions_->at(code->instruction_index())->hydrogen_value();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000331 RecordAndWritePosition(
332 chunk()->graph()->SourcePositionToScriptPosition(value->position()));
danno@chromium.org59400602013-08-13 17:09:37 +0000333
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000334 Comment(";;; <@%d,#%d> "
335 "-------------------- Deferred %s --------------------",
336 code->instruction_index(),
337 code->instr()->hydrogen_value()->id(),
338 code->instr()->Mnemonic());
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000339 __ bind(code->entry());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000340 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000341 Comment(";;; Build frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000342 ASSERT(!frame_is_built_);
343 ASSERT(info()->IsStub());
344 frame_is_built_ = true;
345 // Build the frame in such a way that esi isn't trashed.
346 __ push(rbp); // Caller's frame pointer.
347 __ push(Operand(rbp, StandardFrameConstants::kContextOffset));
348 __ Push(Smi::FromInt(StackFrame::STUB));
349 __ lea(rbp, Operand(rsp, 2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000350 Comment(";;; Deferred code");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000351 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000352 code->Generate();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000353 if (NeedsDeferredFrame()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000354 __ bind(code->done());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000355 Comment(";;; Destroy frame");
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000356 ASSERT(frame_is_built_);
357 frame_is_built_ = false;
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000358 __ movp(rsp, rbp);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000359 __ pop(rbp);
360 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000361 __ jmp(code->exit());
362 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000363 }
364
365 // Deferred code is the last part of the instruction sequence. Mark
366 // the generated code as done unless we bailed out.
367 if (!is_aborted()) status_ = DONE;
368 return !is_aborted();
369}
370
371
372bool LCodeGen::GenerateSafepointTable() {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000373 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000374 safepoints_.Emit(masm(), GetStackSlotCount());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000375 return !is_aborted();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000376}
377
378
379Register LCodeGen::ToRegister(int index) const {
380 return Register::FromAllocationIndex(index);
381}
382
383
384XMMRegister LCodeGen::ToDoubleRegister(int index) const {
385 return XMMRegister::FromAllocationIndex(index);
386}
387
388
389Register LCodeGen::ToRegister(LOperand* op) const {
390 ASSERT(op->IsRegister());
391 return ToRegister(op->index());
392}
393
394
395XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
396 ASSERT(op->IsDoubleRegister());
397 return ToDoubleRegister(op->index());
398}
399
400
401bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
402 return op->IsConstantOperand() &&
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +0000403 chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000404}
405
406
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000407bool LCodeGen::IsSmiConstant(LConstantOperand* op) const {
408 return op->IsConstantOperand() &&
409 chunk_->LookupLiteralRepresentation(op).IsSmi();
410}
411
412
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000413bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const {
414 return op->IsConstantOperand() &&
415 chunk_->LookupLiteralRepresentation(op).IsTagged();
416}
417
418
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000419int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000420 HConstant* constant = chunk_->LookupConstant(op);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000421 return constant->Integer32Value();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000422}
423
424
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000425Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
426 HConstant* constant = chunk_->LookupConstant(op);
427 return Smi::FromInt(constant->Integer32Value());
428}
429
430
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000431double LCodeGen::ToDouble(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000432 HConstant* constant = chunk_->LookupConstant(op);
433 ASSERT(constant->HasDoubleValue());
434 return constant->DoubleValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000435}
436
437
danno@chromium.orgd3c42102013-08-01 16:58:23 +0000438ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const {
439 HConstant* constant = chunk_->LookupConstant(op);
440 ASSERT(constant->HasExternalReferenceValue());
441 return constant->ExternalReferenceValue();
442}
443
444
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000445Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000446 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000447 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000448 return constant->handle(isolate());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000449}
450
451
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000452static int ArgumentsOffsetWithoutFrame(int index) {
453 ASSERT(index < 0);
454 return -(index + 1) * kPointerSize + kPCOnStackSize;
455}
456
457
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000458Operand LCodeGen::ToOperand(LOperand* op) const {
459 // Does not handle registers. In X64 assembler, plain registers are not
460 // representable as an Operand.
461 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000462 if (NeedsEagerFrame()) {
463 return Operand(rbp, StackSlotOffset(op->index()));
464 } else {
465 // Retrieve parameter without eager stack-frame relative to the
466 // stack-pointer.
467 return Operand(rsp, ArgumentsOffsetWithoutFrame(op->index()));
468 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000469}
470
471
472void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000473 Translation* translation) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000474 if (environment == NULL) return;
475
476 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000477 int translation_size = environment->translation_size();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000478 // The output frame height does not include the parameters.
479 int height = translation_size - environment->parameter_count();
480
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000481 WriteTranslation(environment->outer(), translation);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000482 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000483 !info()->closure().is_identical_to(environment->closure());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000484 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000485 ? DefineDeoptimizationLiteral(environment->closure())
486 : Translation::kSelfLiteralId;
487
ulan@chromium.org967e2702012-02-28 09:49:15 +0000488 switch (environment->frame_type()) {
489 case JS_FUNCTION:
490 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
491 break;
492 case JS_CONSTRUCT:
493 translation->BeginConstructStubFrame(closure_id, translation_size);
494 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000495 case JS_GETTER:
496 ASSERT(translation_size == 1);
497 ASSERT(height == 0);
498 translation->BeginGetterStubFrame(closure_id);
499 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000500 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000501 ASSERT(translation_size == 2);
502 ASSERT(height == 0);
503 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000504 break;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000505 case ARGUMENTS_ADAPTOR:
506 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
507 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000508 case STUB:
509 translation->BeginCompiledStubFrame();
510 break;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000511 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000512
danno@chromium.org59400602013-08-13 17:09:37 +0000513 int object_index = 0;
514 int dematerialized_index = 0;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000515 for (int i = 0; i < translation_size; ++i) {
516 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000517 AddToTranslation(environment,
518 translation,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000519 value,
520 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000521 environment->HasUint32ValueAt(i),
522 &object_index,
523 &dematerialized_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000524 }
525}
526
527
danno@chromium.org59400602013-08-13 17:09:37 +0000528void LCodeGen::AddToTranslation(LEnvironment* environment,
529 Translation* translation,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000530 LOperand* op,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000531 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000532 bool is_uint32,
533 int* object_index_pointer,
534 int* dematerialized_index_pointer) {
535 if (op == LEnvironment::materialization_marker()) {
536 int object_index = (*object_index_pointer)++;
537 if (environment->ObjectIsDuplicateAt(object_index)) {
538 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
539 translation->DuplicateObject(dupe_of);
540 return;
541 }
542 int object_length = environment->ObjectLengthAt(object_index);
543 if (environment->ObjectIsArgumentsAt(object_index)) {
544 translation->BeginArgumentsObject(object_length);
545 } else {
546 translation->BeginCapturedObject(object_length);
547 }
548 int dematerialized_index = *dematerialized_index_pointer;
549 int env_offset = environment->translation_size() + dematerialized_index;
550 *dematerialized_index_pointer += object_length;
551 for (int i = 0; i < object_length; ++i) {
552 LOperand* value = environment->values()->at(env_offset + i);
553 AddToTranslation(environment,
554 translation,
555 value,
556 environment->HasTaggedValueAt(env_offset + i),
557 environment->HasUint32ValueAt(env_offset + i),
558 object_index_pointer,
559 dematerialized_index_pointer);
560 }
561 return;
562 }
563
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000564 if (op->IsStackSlot()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000565 if (is_tagged) {
566 translation->StoreStackSlot(op->index());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000567 } else if (is_uint32) {
568 translation->StoreUint32StackSlot(op->index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000569 } else {
570 translation->StoreInt32StackSlot(op->index());
571 }
572 } else if (op->IsDoubleStackSlot()) {
573 translation->StoreDoubleStackSlot(op->index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000574 } else if (op->IsRegister()) {
575 Register reg = ToRegister(op);
576 if (is_tagged) {
577 translation->StoreRegister(reg);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000578 } else if (is_uint32) {
579 translation->StoreUint32Register(reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000580 } else {
581 translation->StoreInt32Register(reg);
582 }
583 } else if (op->IsDoubleRegister()) {
584 XMMRegister reg = ToDoubleRegister(op);
585 translation->StoreDoubleRegister(reg);
586 } else if (op->IsConstantOperand()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000587 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000588 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000589 translation->StoreLiteral(src_index);
590 } else {
591 UNREACHABLE();
592 }
593}
594
595
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000596void LCodeGen::CallCodeGeneric(Handle<Code> code,
597 RelocInfo::Mode mode,
598 LInstruction* instr,
599 SafepointMode safepoint_mode,
600 int argc) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000601 ASSERT(instr != NULL);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000602 __ call(code, mode);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000603 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000604
605 // Signal that we don't inline smi code before these stubs in the
606 // optimizing code generator.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000607 if (code->kind() == Code::BINARY_OP_IC ||
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000608 code->kind() == Code::COMPARE_IC) {
609 __ nop();
610 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000611}
612
613
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000614void LCodeGen::CallCode(Handle<Code> code,
615 RelocInfo::Mode mode,
616 LInstruction* instr) {
617 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0);
618}
619
620
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621void LCodeGen::CallRuntime(const Runtime::Function* function,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000622 int num_arguments,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000623 LInstruction* instr,
624 SaveFPRegsMode save_doubles) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000625 ASSERT(instr != NULL);
626 ASSERT(instr->HasPointerMap());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000627
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000628 __ CallRuntime(function, num_arguments, save_doubles);
629
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000630 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000631}
632
633
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000634void LCodeGen::LoadContextFromDeferred(LOperand* context) {
635 if (context->IsRegister()) {
636 if (!ToRegister(context).is(rsi)) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000637 __ movp(rsi, ToRegister(context));
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000638 }
639 } else if (context->IsStackSlot()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +0000640 __ movp(rsi, ToOperand(context));
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000641 } else if (context->IsConstantOperand()) {
642 HConstant* constant =
643 chunk_->LookupConstant(LConstantOperand::cast(context));
644 __ Move(rsi, Handle<Object>::cast(constant->handle(isolate())));
645 } else {
646 UNREACHABLE();
647 }
648}
649
650
651
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000652void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
653 int argc,
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000654 LInstruction* instr,
655 LOperand* context) {
656 LoadContextFromDeferred(context);
657
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000658 __ CallRuntimeSaveDoubles(id);
659 RecordSafepointWithRegisters(
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000660 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000661}
662
663
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000664void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
665 Safepoint::DeoptMode mode) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000666 if (!environment->HasBeenRegistered()) {
667 // Physical stack frame layout:
668 // -x ............. -4 0 ..................................... y
669 // [incoming arguments] [spill slots] [pushed outgoing arguments]
670
671 // Layout of the environment:
672 // 0 ..................................................... size-1
673 // [parameters] [locals] [expression stack including arguments]
674
675 // Layout of the translation:
676 // 0 ........................................................ size - 1 + 4
677 // [expression stack including arguments] [locals] [4 words] [parameters]
678 // |>------------ translation_size ------------<|
679
680 int frame_count = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000681 int jsframe_count = 0;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000682 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
683 ++frame_count;
ulan@chromium.org967e2702012-02-28 09:49:15 +0000684 if (e->frame_type() == JS_FUNCTION) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000685 ++jsframe_count;
686 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000687 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000688 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000689 WriteTranslation(environment, &translation);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000690 int deoptimization_index = deoptimizations_.length();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000691 int pc_offset = masm()->pc_offset();
692 environment->Register(deoptimization_index,
693 translation.index(),
694 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000695 deoptimizations_.Add(environment, environment->zone());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000696 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000697}
698
699
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000700void LCodeGen::DeoptimizeIf(Condition cc,
701 LEnvironment* environment,
702 Deoptimizer::BailoutType bailout_type) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000703 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000704 ASSERT(environment->HasBeenRegistered());
705 int id = environment->deoptimization_index();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000706 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000707 Address entry =
708 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000709 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +0000710 Abort(kBailoutWasNotPrepared);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000711 return;
712 }
713
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000714 if (DeoptEveryNTimes()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000715 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
716 Label no_deopt;
717 __ pushfq();
718 __ push(rax);
719 Operand count_operand = masm()->ExternalOperand(count, kScratchRegister);
720 __ movl(rax, count_operand);
721 __ subl(rax, Immediate(1));
722 __ j(not_zero, &no_deopt, Label::kNear);
723 if (FLAG_trap_on_deopt) __ int3();
724 __ movl(rax, Immediate(FLAG_deopt_every_n_times));
725 __ movl(count_operand, rax);
726 __ pop(rax);
727 __ popfq();
728 ASSERT(frame_is_built_);
729 __ call(entry, RelocInfo::RUNTIME_ENTRY);
730 __ bind(&no_deopt);
731 __ movl(count_operand, rax);
732 __ pop(rax);
733 __ popfq();
734 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000735
danno@chromium.org59400602013-08-13 17:09:37 +0000736 if (info()->ShouldTrapOnDeopt()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000737 Label done;
738 if (cc != no_condition) {
739 __ j(NegateCondition(cc), &done, Label::kNear);
740 }
741 __ int3();
742 __ bind(&done);
743 }
744
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000745 ASSERT(info()->IsStub() || frame_is_built_);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000746 // Go through jump table if we need to handle condition, build frame, or
747 // restore caller doubles.
748 if (cc == no_condition && frame_is_built_ &&
749 !info()->saves_caller_doubles()) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000750 __ call(entry, RelocInfo::RUNTIME_ENTRY);
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000751 } else {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000752 // We often have several deopts to the same entry, reuse the last
753 // jump entry if this is the case.
ricow@chromium.orgeb96f4f2011-03-09 13:41:48 +0000754 if (jump_table_.is_empty() ||
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000755 jump_table_.last().address != entry ||
756 jump_table_.last().needs_frame != !frame_is_built_ ||
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000757 jump_table_.last().bailout_type != bailout_type) {
758 Deoptimizer::JumpTableEntry table_entry(entry,
759 bailout_type,
760 !frame_is_built_);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000761 jump_table_.Add(table_entry, zone());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000762 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000763 if (cc == no_condition) {
764 __ jmp(&jump_table_.last().label);
765 } else {
766 __ j(cc, &jump_table_.last().label);
767 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000768 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000769}
770
771
danno@chromium.orgaefd6072013-05-14 14:11:47 +0000772void LCodeGen::DeoptimizeIf(Condition cc,
773 LEnvironment* environment) {
774 Deoptimizer::BailoutType bailout_type = info()->IsStub()
775 ? Deoptimizer::LAZY
776 : Deoptimizer::EAGER;
777 DeoptimizeIf(cc, environment, bailout_type);
778}
779
780
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000781void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
782 int length = deoptimizations_.length();
783 if (length == 0) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000784 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000785 factory()->NewDeoptimizationInputData(length, TENURED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000786
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000787 Handle<ByteArray> translations =
788 translations_.CreateByteArray(isolate()->factory());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000789 data->SetTranslationByteArray(*translations);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000790 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000791 data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
792 if (info_->IsOptimizing()) {
793 // Reference to shared function info does not change between phases.
794 AllowDeferredHandleDereference allow_handle_dereference;
795 data->SetSharedFunctionInfo(*info_->shared_info());
796 } else {
797 data->SetSharedFunctionInfo(Smi::FromInt(0));
798 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000799
800 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000801 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000802 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000803 for (int i = 0; i < deoptimization_literals_.length(); i++) {
804 literals->set(i, *deoptimization_literals_[i]);
805 }
806 data->SetLiteralArray(*literals);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000807 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000808
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000809 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000810 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
811
812 // Populate the deoptimization entries.
813 for (int i = 0; i < length; i++) {
814 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000815 data->SetAstId(i, env->ast_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000816 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
817 data->SetArgumentsStackHeight(i,
818 Smi::FromInt(env->arguments_stack_height()));
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000819 data->SetPc(i, Smi::FromInt(env->pc_offset()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000820 }
821 code->set_deoptimization_data(*data);
822}
823
824
825int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
826 int result = deoptimization_literals_.length();
827 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
828 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
829 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000830 deoptimization_literals_.Add(literal, zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000831 return result;
832}
833
834
835void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
836 ASSERT(deoptimization_literals_.length() == 0);
837
838 const ZoneList<Handle<JSFunction> >* inlined_closures =
839 chunk()->inlined_closures();
840
841 for (int i = 0, length = inlined_closures->length();
842 i < length;
843 i++) {
844 DefineDeoptimizationLiteral(inlined_closures->at(i));
845 }
846
847 inlined_function_count_ = deoptimization_literals_.length();
848}
849
850
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000851void LCodeGen::RecordSafepointWithLazyDeopt(
852 LInstruction* instr, SafepointMode safepoint_mode, int argc) {
853 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
854 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
855 } else {
856 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS);
857 RecordSafepointWithRegisters(
858 instr->pointer_map(), argc, Safepoint::kLazyDeopt);
859 }
860}
861
862
ager@chromium.org378b34e2011-01-28 08:04:38 +0000863void LCodeGen::RecordSafepoint(
864 LPointerMap* pointers,
865 Safepoint::Kind kind,
866 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000867 Safepoint::DeoptMode deopt_mode) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000868 ASSERT(kind == expected_safepoint_kind_);
869
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000870 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000871
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000872 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000873 kind, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000874 for (int i = 0; i < operands->length(); i++) {
875 LOperand* pointer = operands->at(i);
876 if (pointer->IsStackSlot()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000877 safepoint.DefinePointerSlot(pointer->index(), zone());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000878 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000879 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000880 }
881 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000882}
883
884
885void LCodeGen::RecordSafepoint(LPointerMap* pointers,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000886 Safepoint::DeoptMode deopt_mode) {
887 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000888}
889
890
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000891void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000892 LPointerMap empty_pointers(zone());
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000893 RecordSafepoint(&empty_pointers, deopt_mode);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000894}
895
896
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000897void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
898 int arguments,
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000899 Safepoint::DeoptMode deopt_mode) {
900 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000901}
902
903
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000904void LCodeGen::RecordAndWritePosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000905 if (position == RelocInfo::kNoPosition) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000906 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000907 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +0000908}
909
910
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000911static const char* LabelType(LLabel* label) {
912 if (label->is_loop_header()) return " (loop header)";
913 if (label->is_osr_entry()) return " (OSR entry)";
914 return "";
915}
916
917
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000918void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000919 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
920 current_instruction_,
921 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000922 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000923 LabelType(label));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000924 __ bind(label->label());
925 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000926 DoGap(label);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000927}
928
929
930void LCodeGen::DoParallelMove(LParallelMove* move) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +0000931 resolver_.Resolve(move);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000932}
933
934
935void LCodeGen::DoGap(LGap* gap) {
936 for (int i = LGap::FIRST_INNER_POSITION;
937 i <= LGap::LAST_INNER_POSITION;
938 i++) {
939 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
940 LParallelMove* move = gap->GetParallelMove(inner_pos);
941 if (move != NULL) DoParallelMove(move);
942 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000943}
944
945
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000946void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
947 DoGap(instr);
948}
949
950
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000951void LCodeGen::DoParameter(LParameter* instr) {
952 // Nothing to do.
953}
954
955
956void LCodeGen::DoCallStub(LCallStub* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +0000957 ASSERT(ToRegister(instr->context()).is(rsi));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000958 ASSERT(ToRegister(instr->result()).is(rax));
959 switch (instr->hydrogen()->major_key()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000960 case CodeStub::RegExpExec: {
961 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000962 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000963 break;
964 }
965 case CodeStub::SubString: {
966 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000967 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000968 break;
969 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000970 case CodeStub::StringCompare: {
971 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000972 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000973 break;
974 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000975 default:
976 UNREACHABLE();
977 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000978}
979
980
981void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000982 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000983}
984
985
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +0000986void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
987 Register dividend = ToRegister(instr->dividend());
988 int32_t divisor = instr->divisor();
989 ASSERT(dividend.is(ToRegister(instr->result())));
990
991 // Theoretically, a variation of the branch-free code for integer division by
992 // a power of 2 (calculating the remainder via an additional multiplication
993 // (which gets simplified to an 'and') and subtraction) should be faster, and
994 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
995 // indicate that positive dividends are heavily favored, so the branching
996 // version performs better.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000997 HMod* hmod = instr->hydrogen();
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +0000998 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
999 Label dividend_is_not_negative, done;
1000 if (hmod->left()->CanBeNegative()) {
1001 __ testl(dividend, dividend);
1002 __ j(not_sign, &dividend_is_not_negative, Label::kNear);
1003 // Note that this is correct even for kMinInt operands.
1004 __ negl(dividend);
1005 __ andl(dividend, Immediate(mask));
1006 __ negl(dividend);
1007 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001008 DeoptimizeIf(zero, instr->environment());
1009 }
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001010 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001011 }
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001012
1013 __ bind(&dividend_is_not_negative);
1014 __ andl(dividend, Immediate(mask));
1015 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001016}
1017
1018
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001019void LCodeGen::DoModI(LModI* instr) {
1020 if (instr->hydrogen()->RightIsPowerOf2()) {
1021 return DoModByPowerOf2I(reinterpret_cast<LModByPowerOf2I*>(instr));
1022 }
1023 HMod* hmod = instr->hydrogen();
1024 HValue* left = hmod->left();
1025 HValue* right = hmod->right();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001026
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001027 Register left_reg = ToRegister(instr->left());
1028 ASSERT(left_reg.is(rax));
1029 Register right_reg = ToRegister(instr->right());
1030 ASSERT(!right_reg.is(rax));
1031 ASSERT(!right_reg.is(rdx));
1032 Register result_reg = ToRegister(instr->result());
1033 ASSERT(result_reg.is(rdx));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001034
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001035 Label done;
1036 // Check for x % 0, idiv would signal a divide error. We have to
1037 // deopt in this case because we can't return a NaN.
1038 if (right->CanBeZero()) {
1039 __ testl(right_reg, right_reg);
1040 DeoptimizeIf(zero, instr->environment());
1041 }
1042
1043 // Check for kMinInt % -1, idiv would signal a divide error. We
1044 // have to deopt if we care about -0, because we can't return that.
1045 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
1046 Label no_overflow_possible;
1047 __ cmpl(left_reg, Immediate(kMinInt));
1048 __ j(not_zero, &no_overflow_possible, Label::kNear);
1049 __ cmpl(right_reg, Immediate(-1));
1050 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1051 DeoptimizeIf(equal, instr->environment());
1052 } else {
1053 __ j(not_equal, &no_overflow_possible, Label::kNear);
1054 __ Set(result_reg, 0);
1055 __ jmp(&done, Label::kNear);
1056 }
1057 __ bind(&no_overflow_possible);
1058 }
1059
1060 // Sign extend dividend in eax into edx:eax, since we are using only the low
1061 // 32 bits of the values.
1062 __ cdq();
1063
1064 // If we care about -0, test if the dividend is <0 and the result is 0.
1065 if (left->CanBeNegative() &&
1066 hmod->CanBeZero() &&
1067 hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1068 Label positive_left;
1069 __ testl(left_reg, left_reg);
1070 __ j(not_sign, &positive_left, Label::kNear);
1071 __ idivl(right_reg);
1072 __ testl(result_reg, result_reg);
1073 DeoptimizeIf(zero, instr->environment());
1074 __ jmp(&done, Label::kNear);
1075 __ bind(&positive_left);
1076 }
1077 __ idivl(right_reg);
1078 __ bind(&done);
1079}
1080
1081
1082void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
1083 Register dividend = ToRegister(instr->dividend());
1084 int32_t divisor = instr->divisor();
1085 ASSERT(dividend.is(ToRegister(instr->result())));
1086
1087 // If the divisor is positive, things are easy: There can be no deopts and we
1088 // can simply do an arithmetic right shift.
1089 if (divisor == 1) return;
1090 int32_t shift = WhichPowerOf2Abs(divisor);
1091 if (divisor > 1) {
1092 __ sarl(dividend, Immediate(shift));
1093 return;
1094 }
1095
1096 // If the divisor is negative, we have to negate and handle edge cases.
1097 Label not_kmin_int, done;
1098 __ negl(dividend);
1099 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1100 DeoptimizeIf(zero, instr->environment());
1101 }
1102 if (instr->hydrogen()->left()->RangeCanInclude(kMinInt)) {
1103 // Note that we could emit branch-free code, but that would need one more
1104 // register.
1105 __ j(no_overflow, &not_kmin_int, Label::kNear);
1106 if (divisor == -1) {
1107 DeoptimizeIf(no_condition, instr->environment());
1108 } else {
1109 __ movl(dividend, Immediate(kMinInt / divisor));
1110 __ jmp(&done, Label::kNear);
1111 }
1112 }
1113 __ bind(&not_kmin_int);
1114 __ sarl(dividend, Immediate(shift));
1115 __ bind(&done);
1116}
1117
1118
1119void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
1120 Register dividend = ToRegister(instr->dividend());
1121 int32_t divisor = instr->divisor();
1122 Register temp = ToRegister(instr->temp());
1123 Register result = ToRegister(instr->result());
1124
1125 if (divisor == 0) {
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001126 DeoptimizeIf(no_condition, instr->environment());
1127 return;
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001128 }
1129
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001130 // Find b which: 2^b < divisor_abs < 2^(b+1).
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001131 uint32_t divisor_abs = abs(divisor);
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001132 unsigned b = 31 - CompilerIntrinsics::CountLeadingZeros(divisor_abs);
1133 unsigned shift = 32 + b; // Precision +1bit (effectively).
1134 double multiplier_f =
1135 static_cast<double>(static_cast<uint64_t>(1) << shift) / divisor_abs;
1136 int64_t multiplier;
1137 if (multiplier_f - std::floor(multiplier_f) < 0.5) {
1138 multiplier = static_cast<int64_t>(std::floor(multiplier_f));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001139 } else {
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001140 multiplier = static_cast<int64_t>(std::floor(multiplier_f)) + 1;
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001141 }
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001142 // The multiplier is a uint32.
1143 ASSERT(multiplier > 0 &&
1144 multiplier < (static_cast<int64_t>(1) << 32));
1145 // The multiply is int64, so sign-extend to r64.
1146 __ movsxlq(temp, dividend);
1147 if (divisor < 0 &&
1148 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1149 __ neg(temp);
1150 DeoptimizeIf(zero, instr->environment());
1151 }
1152 __ Set(result, multiplier);
1153 // Result just fit in r64, because it's int32 * uint32.
1154 __ imul(result, temp);
1155
1156 __ addq(result, Immediate(1 << 30));
1157 __ sar(result, Immediate(shift));
1158}
1159
1160
1161void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
1162 Register dividend = ToRegister(instr->dividend());
1163 int32_t divisor = instr->divisor();
1164 Register result = ToRegister(instr->result());
1165 ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
1166 ASSERT(!result.is(dividend));
1167
1168 // Check for (0 / -x) that will produce negative zero.
1169 HDiv* hdiv = instr->hydrogen();
1170 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) &&
1171 hdiv->left()->RangeCanInclude(0) && divisor < 0) {
1172 __ testl(dividend, dividend);
1173 DeoptimizeIf(zero, instr->environment());
1174 }
1175 // Check for (kMinInt / -1).
1176 if (hdiv->CheckFlag(HValue::kCanOverflow) &&
1177 hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1) {
1178 __ cmpl(dividend, Immediate(kMinInt));
1179 DeoptimizeIf(zero, instr->environment());
1180 }
1181 // Deoptimize if remainder will not be 0.
1182 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1183 divisor != 1 && divisor != -1) {
1184 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
1185 __ testl(dividend, Immediate(mask));
1186 DeoptimizeIf(not_zero, instr->environment());
1187 }
1188 __ Move(result, dividend);
1189 int32_t shift = WhichPowerOf2Abs(divisor);
1190 if (shift > 0) {
1191 // The arithmetic shift is always OK, the 'if' is an optimization only.
1192 if (shift > 1) __ sarl(result, Immediate(31));
1193 __ shrl(result, Immediate(32 - shift));
1194 __ addl(result, dividend);
1195 __ sarl(result, Immediate(shift));
1196 }
1197 if (divisor < 0) __ negl(result);
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001198}
1199
1200
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001201void LCodeGen::DoDivI(LDivI* instr) {
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001202 Register dividend = ToRegister(instr->left());
1203 Register divisor = ToRegister(instr->right());
1204 Register remainder = ToRegister(instr->temp());
1205 Register result = ToRegister(instr->result());
1206 ASSERT(dividend.is(rax));
1207 ASSERT(remainder.is(rdx));
1208 ASSERT(result.is(rax));
1209 ASSERT(!divisor.is(rax));
1210 ASSERT(!divisor.is(rdx));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001211
1212 // Check for x / 0.
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001213 HBinaryOperation* hdiv = instr->hydrogen();
1214 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
1215 __ testl(divisor, divisor);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001216 DeoptimizeIf(zero, instr->environment());
1217 }
1218
1219 // Check for (0 / -x) that will produce negative zero.
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001220 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
1221 Label dividend_not_zero;
1222 __ testl(dividend, dividend);
1223 __ j(not_zero, &dividend_not_zero, Label::kNear);
1224 __ testl(divisor, divisor);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001225 DeoptimizeIf(sign, instr->environment());
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001226 __ bind(&dividend_not_zero);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001227 }
1228
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001229 // Check for (kMinInt / -1).
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001230 if (hdiv->CheckFlag(HValue::kCanOverflow)) {
1231 Label dividend_not_min_int;
1232 __ cmpl(dividend, Immediate(kMinInt));
1233 __ j(not_zero, &dividend_not_min_int, Label::kNear);
1234 __ cmpl(divisor, Immediate(-1));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001235 DeoptimizeIf(zero, instr->environment());
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001236 __ bind(&dividend_not_min_int);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001237 }
1238
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001239 // Sign extend to rdx (= remainder).
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001240 __ cdq();
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001241 __ idivl(divisor);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001242
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001243 if (instr->is_flooring()) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001244 Label done;
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001245 __ testl(remainder, remainder);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001246 __ j(zero, &done, Label::kNear);
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001247 __ xorl(remainder, divisor);
1248 __ sarl(remainder, Immediate(31));
1249 __ addl(result, remainder);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001250 __ bind(&done);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001251 } else if (!instr->hydrogen()->CheckFlag(
1252 HInstruction::kAllUsesTruncatingToInt32)) {
1253 // Deoptimize if remainder is not 0.
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00001254 __ testl(remainder, remainder);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00001255 DeoptimizeIf(not_zero, instr->environment());
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001256 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001257}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001258
1259
1260void LCodeGen::DoMulI(LMulI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001261 Register left = ToRegister(instr->left());
1262 LOperand* right = instr->right();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001263
1264 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001265 if (instr->hydrogen_value()->representation().IsSmi()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001266 __ movp(kScratchRegister, left);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001267 } else {
1268 __ movl(kScratchRegister, left);
1269 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001270 }
1271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001272 bool can_overflow =
1273 instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001274 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001275 int32_t right_value = ToInteger32(LConstantOperand::cast(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 if (right_value == -1) {
1277 __ negl(left);
1278 } else if (right_value == 0) {
1279 __ xorl(left, left);
1280 } else if (right_value == 2) {
1281 __ addl(left, left);
1282 } else if (!can_overflow) {
1283 // If the multiplication is known to not overflow, we
1284 // can use operations that don't set the overflow flag
1285 // correctly.
1286 switch (right_value) {
1287 case 1:
1288 // Do nothing.
1289 break;
1290 case 3:
1291 __ leal(left, Operand(left, left, times_2, 0));
1292 break;
1293 case 4:
1294 __ shll(left, Immediate(2));
1295 break;
1296 case 5:
1297 __ leal(left, Operand(left, left, times_4, 0));
1298 break;
1299 case 8:
1300 __ shll(left, Immediate(3));
1301 break;
1302 case 9:
1303 __ leal(left, Operand(left, left, times_8, 0));
1304 break;
1305 case 16:
1306 __ shll(left, Immediate(4));
1307 break;
1308 default:
1309 __ imull(left, left, Immediate(right_value));
1310 break;
1311 }
1312 } else {
1313 __ imull(left, left, Immediate(right_value));
1314 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001315 } else if (right->IsStackSlot()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001316 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001317 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001318 __ imul(left, ToOperand(right));
1319 } else {
1320 __ imull(left, ToOperand(right));
1321 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001322 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001323 if (instr->hydrogen_value()->representation().IsSmi()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001324 __ SmiToInteger64(left, left);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001325 __ imul(left, ToRegister(right));
1326 } else {
1327 __ imull(left, ToRegister(right));
1328 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001329 }
1330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 if (can_overflow) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001332 DeoptimizeIf(overflow, instr->environment());
1333 }
1334
1335 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1336 // Bail out if the result is supposed to be negative zero.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001337 Label done;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001338 if (instr->hydrogen_value()->representation().IsSmi()) {
1339 __ testq(left, left);
1340 } else {
1341 __ testl(left, left);
1342 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001343 __ j(not_zero, &done, Label::kNear);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001344 if (right->IsConstantOperand()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001345 // Constant can't be represented as Smi due to immediate size limit.
1346 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001347 if (ToInteger32(LConstantOperand::cast(right)) < 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001348 DeoptimizeIf(no_condition, instr->environment());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001349 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) {
1350 __ cmpl(kScratchRegister, Immediate(0));
1351 DeoptimizeIf(less, instr->environment());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001352 }
1353 } else if (right->IsStackSlot()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001354 if (instr->hydrogen_value()->representation().IsSmi()) {
1355 __ or_(kScratchRegister, ToOperand(right));
1356 } else {
1357 __ orl(kScratchRegister, ToOperand(right));
1358 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001359 DeoptimizeIf(sign, instr->environment());
1360 } else {
1361 // Test the non-zero operand for negative sign.
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001362 if (instr->hydrogen_value()->representation().IsSmi()) {
1363 __ or_(kScratchRegister, ToRegister(right));
1364 } else {
1365 __ orl(kScratchRegister, ToRegister(right));
1366 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001367 DeoptimizeIf(sign, instr->environment());
1368 }
1369 __ bind(&done);
1370 }
1371}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001372
1373
1374void LCodeGen::DoBitI(LBitI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001375 LOperand* left = instr->left();
1376 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001377 ASSERT(left->Equals(instr->result()));
1378 ASSERT(left->IsRegister());
1379
1380 if (right->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00001381 int32_t right_operand = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001382 switch (instr->op()) {
1383 case Token::BIT_AND:
1384 __ andl(ToRegister(left), Immediate(right_operand));
1385 break;
1386 case Token::BIT_OR:
1387 __ orl(ToRegister(left), Immediate(right_operand));
1388 break;
1389 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001390 if (right_operand == int32_t(~0)) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001391 __ notl(ToRegister(left));
danno@chromium.org59400602013-08-13 17:09:37 +00001392 } else {
1393 __ xorl(ToRegister(left), Immediate(right_operand));
1394 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001395 break;
1396 default:
1397 UNREACHABLE();
1398 break;
1399 }
1400 } else if (right->IsStackSlot()) {
1401 switch (instr->op()) {
1402 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001403 __ and_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001404 break;
1405 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001406 __ or_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001407 break;
1408 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001409 __ xor_(ToRegister(left), ToOperand(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001410 break;
1411 default:
1412 UNREACHABLE();
1413 break;
1414 }
1415 } else {
1416 ASSERT(right->IsRegister());
1417 switch (instr->op()) {
1418 case Token::BIT_AND:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001419 __ and_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001420 break;
1421 case Token::BIT_OR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001422 __ or_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001423 break;
1424 case Token::BIT_XOR:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001425 __ xor_(ToRegister(left), ToRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001426 break;
1427 default:
1428 UNREACHABLE();
1429 break;
1430 }
1431 }
1432}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001433
1434
1435void LCodeGen::DoShiftI(LShiftI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001436 LOperand* left = instr->left();
1437 LOperand* right = instr->right();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001438 ASSERT(left->Equals(instr->result()));
1439 ASSERT(left->IsRegister());
1440 if (right->IsRegister()) {
1441 ASSERT(ToRegister(right).is(rcx));
1442
1443 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001444 case Token::ROR:
1445 __ rorl_cl(ToRegister(left));
1446 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001447 case Token::SAR:
1448 __ sarl_cl(ToRegister(left));
1449 break;
1450 case Token::SHR:
1451 __ shrl_cl(ToRegister(left));
1452 if (instr->can_deopt()) {
1453 __ testl(ToRegister(left), ToRegister(left));
1454 DeoptimizeIf(negative, instr->environment());
1455 }
1456 break;
1457 case Token::SHL:
1458 __ shll_cl(ToRegister(left));
1459 break;
1460 default:
1461 UNREACHABLE();
1462 break;
1463 }
1464 } else {
danno@chromium.org59400602013-08-13 17:09:37 +00001465 int32_t value = ToInteger32(LConstantOperand::cast(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001466 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1467 switch (instr->op()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001468 case Token::ROR:
1469 if (shift_count != 0) {
1470 __ rorl(ToRegister(left), Immediate(shift_count));
1471 }
1472 break;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001473 case Token::SAR:
1474 if (shift_count != 0) {
1475 __ sarl(ToRegister(left), Immediate(shift_count));
1476 }
1477 break;
1478 case Token::SHR:
1479 if (shift_count == 0 && instr->can_deopt()) {
1480 __ testl(ToRegister(left), ToRegister(left));
1481 DeoptimizeIf(negative, instr->environment());
1482 } else {
1483 __ shrl(ToRegister(left), Immediate(shift_count));
1484 }
1485 break;
1486 case Token::SHL:
1487 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001488 if (instr->hydrogen_value()->representation().IsSmi()) {
1489 __ shl(ToRegister(left), Immediate(shift_count));
1490 } else {
1491 __ shll(ToRegister(left), Immediate(shift_count));
1492 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001493 }
1494 break;
1495 default:
1496 UNREACHABLE();
1497 break;
1498 }
1499 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001500}
1501
1502
1503void LCodeGen::DoSubI(LSubI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001504 LOperand* left = instr->left();
1505 LOperand* right = instr->right();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001506 ASSERT(left->Equals(instr->result()));
1507
1508 if (right->IsConstantOperand()) {
1509 __ subl(ToRegister(left),
1510 Immediate(ToInteger32(LConstantOperand::cast(right))));
1511 } else if (right->IsRegister()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001512 if (instr->hydrogen_value()->representation().IsSmi()) {
1513 __ subq(ToRegister(left), ToRegister(right));
1514 } else {
1515 __ subl(ToRegister(left), ToRegister(right));
1516 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001517 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001518 if (instr->hydrogen_value()->representation().IsSmi()) {
1519 __ subq(ToRegister(left), ToOperand(right));
1520 } else {
1521 __ subl(ToRegister(left), ToOperand(right));
1522 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001523 }
1524
1525 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1526 DeoptimizeIf(overflow, instr->environment());
1527 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001528}
1529
1530
1531void LCodeGen::DoConstantI(LConstantI* instr) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001532 __ Set(ToRegister(instr->result()), instr->value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001533}
1534
1535
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001536void LCodeGen::DoConstantS(LConstantS* instr) {
1537 __ Move(ToRegister(instr->result()), instr->value());
1538}
1539
1540
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001541void LCodeGen::DoConstantD(LConstantD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001542 ASSERT(instr->result()->IsDoubleRegister());
1543 XMMRegister res = ToDoubleRegister(instr->result());
1544 double v = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001545 uint64_t int_val = BitCast<uint64_t, double>(v);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001546 // Use xor to produce +0.0 in a fast and compact way, but avoid to
1547 // do so if the constant is -0.0.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001548 if (int_val == 0) {
danno@chromium.org160a7b02011-04-18 15:51:38 +00001549 __ xorps(res, res);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001550 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001551 Register tmp = ToRegister(instr->temp());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001552 __ Set(tmp, int_val);
1553 __ movq(res, tmp);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001554 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001555}
1556
1557
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001558void LCodeGen::DoConstantE(LConstantE* instr) {
1559 __ LoadAddress(ToRegister(instr->result()), instr->value());
1560}
1561
1562
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001563void LCodeGen::DoConstantT(LConstantT* instr) {
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001564 Handle<Object> value = instr->value(isolate());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00001565 __ Move(ToRegister(instr->result()), value);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001566}
1567
1568
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001569void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1570 Register result = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001571 Register map = ToRegister(instr->value());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001572 __ EnumLength(result, map);
1573}
1574
1575
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001576void LCodeGen::DoDateField(LDateField* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001577 Register object = ToRegister(instr->date());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001578 Register result = ToRegister(instr->result());
1579 Smi* index = instr->index();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001580 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001581 ASSERT(object.is(result));
1582 ASSERT(object.is(rax));
1583
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001584 Condition cc = masm()->CheckSmi(object);
1585 DeoptimizeIf(cc, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001586 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001587 DeoptimizeIf(not_equal, instr->environment());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001588
1589 if (index->value() == 0) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001590 __ movp(result, FieldOperand(object, JSDate::kValueOffset));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001591 } else {
1592 if (index->value() < JSDate::kFirstUncachedField) {
1593 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001594 Operand stamp_operand = __ ExternalOperand(stamp);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001595 __ movp(kScratchRegister, stamp_operand);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001596 __ cmpq(kScratchRegister, FieldOperand(object,
1597 JSDate::kCacheStampOffset));
1598 __ j(not_equal, &runtime, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001599 __ movp(result, FieldOperand(object, JSDate::kValueOffset +
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001600 kPointerSize * index->value()));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001601 __ jmp(&done, Label::kNear);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001602 }
1603 __ bind(&runtime);
1604 __ PrepareCallCFunction(2);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001605 __ movp(arg_reg_1, object);
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00001606 __ Move(arg_reg_2, index, Assembler::RelocInfoNone());
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001607 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001608 __ bind(&done);
1609 }
1610}
1611
1612
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001613Operand LCodeGen::BuildSeqStringOperand(Register string,
1614 LOperand* index,
1615 String::Encoding encoding) {
1616 if (index->IsConstantOperand()) {
1617 int offset = ToInteger32(LConstantOperand::cast(index));
1618 if (encoding == String::TWO_BYTE_ENCODING) {
1619 offset *= kUC16Size;
1620 }
1621 STATIC_ASSERT(kCharSize == 1);
1622 return FieldOperand(string, SeqString::kHeaderSize + offset);
1623 }
1624 return FieldOperand(
1625 string, ToRegister(index),
1626 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2,
1627 SeqString::kHeaderSize);
1628}
1629
1630
1631void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1632 String::Encoding encoding = instr->hydrogen()->encoding();
1633 Register result = ToRegister(instr->result());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001634 Register string = ToRegister(instr->string());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001635
1636 if (FLAG_debug_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001637 __ push(string);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001638 __ movp(string, FieldOperand(string, HeapObject::kMapOffset));
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001639 __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001640
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001641 __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001642 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1643 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001644 __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING
1645 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00001646 __ Check(equal, kUnexpectedStringType);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001647 __ pop(string);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001648 }
1649
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001650 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001651 if (encoding == String::ONE_BYTE_ENCODING) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001652 __ movzxbl(result, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001653 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001654 __ movzxwl(result, operand);
1655 }
1656}
1657
1658
1659void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1660 String::Encoding encoding = instr->hydrogen()->encoding();
1661 Register string = ToRegister(instr->string());
1662
1663 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001664 Register value = ToRegister(instr->value());
1665 Register index = ToRegister(instr->index());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001666 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1667 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001668 int encoding_mask =
1669 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1670 ? one_byte_seq_type : two_byte_seq_type;
1671 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001672 }
1673
1674 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1675 if (instr->value()->IsConstantOperand()) {
1676 int value = ToInteger32(LConstantOperand::cast(instr->value()));
1677 ASSERT_LE(0, value);
1678 if (encoding == String::ONE_BYTE_ENCODING) {
1679 ASSERT_LE(value, String::kMaxOneByteCharCode);
1680 __ movb(operand, Immediate(value));
1681 } else {
1682 ASSERT_LE(value, String::kMaxUtf16CodeUnit);
1683 __ movw(operand, Immediate(value));
1684 }
1685 } else {
1686 Register value = ToRegister(instr->value());
1687 if (encoding == String::ONE_BYTE_ENCODING) {
1688 __ movb(operand, value);
1689 } else {
1690 __ movw(operand, value);
1691 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001692 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001693}
1694
1695
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001696void LCodeGen::DoAddI(LAddI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001697 LOperand* left = instr->left();
1698 LOperand* right = instr->right();
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001699
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001700 Representation target_rep = instr->hydrogen()->representation();
1701 bool is_q = target_rep.IsSmi() || target_rep.IsExternal();
1702
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001703 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) {
1704 if (right->IsConstantOperand()) {
1705 int32_t offset = ToInteger32(LConstantOperand::cast(right));
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001706 if (is_q) {
1707 __ lea(ToRegister(instr->result()),
1708 MemOperand(ToRegister(left), offset));
1709 } else {
1710 __ leal(ToRegister(instr->result()),
1711 MemOperand(ToRegister(left), offset));
1712 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001713 } else {
1714 Operand address(ToRegister(left), ToRegister(right), times_1, 0);
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001715 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001716 __ lea(ToRegister(instr->result()), address);
1717 } else {
1718 __ leal(ToRegister(instr->result()), address);
1719 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001720 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001721 } else {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001722 if (right->IsConstantOperand()) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001723 if (is_q) {
1724 __ addq(ToRegister(left),
1725 Immediate(ToInteger32(LConstantOperand::cast(right))));
1726 } else {
1727 __ addl(ToRegister(left),
1728 Immediate(ToInteger32(LConstantOperand::cast(right))));
1729 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001730 } else if (right->IsRegister()) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001731 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001732 __ addq(ToRegister(left), ToRegister(right));
1733 } else {
1734 __ addl(ToRegister(left), ToRegister(right));
1735 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001736 } else {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001737 if (is_q) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001738 __ addq(ToRegister(left), ToOperand(right));
1739 } else {
1740 __ addl(ToRegister(left), ToOperand(right));
1741 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001742 }
1743 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1744 DeoptimizeIf(overflow, instr->environment());
1745 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001746 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001747}
1748
1749
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001750void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001751 LOperand* left = instr->left();
1752 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001753 ASSERT(left->Equals(instr->result()));
1754 HMathMinMax::Operation operation = instr->hydrogen()->operation();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001755 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001756 Label return_left;
1757 Condition condition = (operation == HMathMinMax::kMathMin)
1758 ? less_equal
1759 : greater_equal;
1760 Register left_reg = ToRegister(left);
1761 if (right->IsConstantOperand()) {
1762 Immediate right_imm =
1763 Immediate(ToInteger32(LConstantOperand::cast(right)));
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001764 ASSERT(!instr->hydrogen_value()->representation().IsSmi());
ulan@chromium.org4121f232012-12-27 15:57:11 +00001765 __ cmpl(left_reg, right_imm);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001766 __ j(condition, &return_left, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001767 __ movp(left_reg, right_imm);
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001768 } else if (right->IsRegister()) {
1769 Register right_reg = ToRegister(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001770 if (instr->hydrogen_value()->representation().IsSmi()) {
1771 __ cmpq(left_reg, right_reg);
1772 } else {
1773 __ cmpl(left_reg, right_reg);
1774 }
jkummerow@chromium.org67255be2012-09-05 16:44:50 +00001775 __ j(condition, &return_left, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001776 __ movp(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001777 } else {
1778 Operand right_op = ToOperand(right);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001779 if (instr->hydrogen_value()->representation().IsSmi()) {
1780 __ cmpq(left_reg, right_op);
1781 } else {
1782 __ cmpl(left_reg, right_op);
1783 }
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001784 __ j(condition, &return_left, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001785 __ movp(left_reg, right_op);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001786 }
1787 __ bind(&return_left);
1788 } else {
1789 ASSERT(instr->hydrogen()->representation().IsDouble());
1790 Label check_nan_left, check_zero, return_left, return_right;
1791 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
1792 XMMRegister left_reg = ToDoubleRegister(left);
1793 XMMRegister right_reg = ToDoubleRegister(right);
1794 __ ucomisd(left_reg, right_reg);
1795 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN.
1796 __ j(equal, &check_zero, Label::kNear); // left == right.
1797 __ j(condition, &return_left, Label::kNear);
1798 __ jmp(&return_right, Label::kNear);
1799
1800 __ bind(&check_zero);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001801 XMMRegister xmm_scratch = double_scratch0();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001802 __ xorps(xmm_scratch, xmm_scratch);
1803 __ ucomisd(left_reg, xmm_scratch);
1804 __ j(not_equal, &return_left, Label::kNear); // left == right != 0.
1805 // At this point, both left and right are either 0 or -0.
1806 if (operation == HMathMinMax::kMathMin) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001807 __ orps(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001808 } else {
1809 // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
1810 __ addsd(left_reg, right_reg);
1811 }
1812 __ jmp(&return_left, Label::kNear);
1813
1814 __ bind(&check_nan_left);
1815 __ ucomisd(left_reg, left_reg); // NaN check.
1816 __ j(parity_even, &return_left, Label::kNear);
1817 __ bind(&return_right);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001818 __ movaps(left_reg, right_reg);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001819
1820 __ bind(&return_left);
1821 }
1822}
1823
1824
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001825void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001826 XMMRegister left = ToDoubleRegister(instr->left());
1827 XMMRegister right = ToDoubleRegister(instr->right());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001828 XMMRegister result = ToDoubleRegister(instr->result());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001829 // All operations except MOD are computed in-place.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001830 ASSERT(instr->op() == Token::MOD || left.is(result));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001831 switch (instr->op()) {
1832 case Token::ADD:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001833 __ addsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001834 break;
1835 case Token::SUB:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001836 __ subsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001837 break;
1838 case Token::MUL:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001839 __ mulsd(left, right);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001840 break;
1841 case Token::DIV:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001842 __ divsd(left, right);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001843 // Don't delete this mov. It may improve performance on some CPUs,
1844 // when there is a mulsd depending on the result
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001845 __ movaps(left, left);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001846 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001847 case Token::MOD: {
1848 XMMRegister xmm_scratch = double_scratch0();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001849 __ PrepareCallCFunction(2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001850 __ movaps(xmm_scratch, left);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001851 ASSERT(right.is(xmm1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001853 ExternalReference::mod_two_doubles_operation(isolate()), 2);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001854 __ movaps(result, xmm_scratch);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001855 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001856 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001857 default:
1858 UNREACHABLE();
1859 break;
1860 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001861}
1862
1863
1864void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00001865 ASSERT(ToRegister(instr->context()).is(rsi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001866 ASSERT(ToRegister(instr->left()).is(rdx));
1867 ASSERT(ToRegister(instr->right()).is(rax));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001868 ASSERT(ToRegister(instr->result()).is(rax));
1869
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001870 BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001871 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001872 __ nop(); // Signals no inlined code.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001873}
1874
1875
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001876template<class InstrType>
1877void LCodeGen::EmitBranch(InstrType instr, Condition cc) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001878 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001879 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001880
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001881 int next_block = GetNextEmittedBlock();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001882
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001883 if (right_block == left_block || cc == no_condition) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001884 EmitGoto(left_block);
1885 } else if (left_block == next_block) {
1886 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1887 } else if (right_block == next_block) {
1888 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1889 } else {
1890 __ j(cc, chunk_->GetAssemblyLabel(left_block));
1891 if (cc != always) {
1892 __ jmp(chunk_->GetAssemblyLabel(right_block));
1893 }
1894 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001895}
1896
1897
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00001898template<class InstrType>
1899void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) {
1900 int false_block = instr->FalseDestination(chunk_);
1901 __ j(cc, chunk_->GetAssemblyLabel(false_block));
1902}
1903
1904
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001905void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1906 __ int3();
1907}
1908
1909
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001910void LCodeGen::DoBranch(LBranch* instr) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001911 Representation r = instr->hydrogen()->value()->representation();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001912 if (r.IsInteger32()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001913 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001914 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001915 __ testl(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001916 EmitBranch(instr, not_zero);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001917 } else if (r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001918 ASSERT(!info()->IsStub());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001919 Register reg = ToRegister(instr->value());
1920 __ testq(reg, reg);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001921 EmitBranch(instr, not_zero);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001922 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001923 ASSERT(!info()->IsStub());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001924 XMMRegister reg = ToDoubleRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001925 XMMRegister xmm_scratch = double_scratch0();
1926 __ xorps(xmm_scratch, xmm_scratch);
1927 __ ucomisd(reg, xmm_scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001928 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001929 } else {
1930 ASSERT(r.IsTagged());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001931 Register reg = ToRegister(instr->value());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001932 HType type = instr->hydrogen()->value()->type();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001933 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001934 ASSERT(!info()->IsStub());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001935 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001936 EmitBranch(instr, equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001937 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001938 ASSERT(!info()->IsStub());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001939 __ SmiCompare(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001940 EmitBranch(instr, not_equal);
1941 } else if (type.IsJSArray()) {
1942 ASSERT(!info()->IsStub());
1943 EmitBranch(instr, no_condition);
1944 } else if (type.IsHeapNumber()) {
1945 ASSERT(!info()->IsStub());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001946 XMMRegister xmm_scratch = double_scratch0();
1947 __ xorps(xmm_scratch, xmm_scratch);
1948 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001949 EmitBranch(instr, not_equal);
1950 } else if (type.IsString()) {
1951 ASSERT(!info()->IsStub());
1952 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
1953 EmitBranch(instr, not_equal);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001954 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001955 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1956 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001957 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001958
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001959 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1960 // undefined -> false.
1961 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001962 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001963 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001964 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1965 // true -> true.
1966 __ CompareRoot(reg, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001967 __ j(equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001968 // false -> false.
1969 __ CompareRoot(reg, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001970 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001971 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001972 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1973 // 'null' -> false.
1974 __ CompareRoot(reg, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001975 __ j(equal, instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001976 }
1977
1978 if (expected.Contains(ToBooleanStub::SMI)) {
1979 // Smis: 0 -> false, all other -> true.
1980 __ Cmp(reg, Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001981 __ j(equal, instr->FalseLabel(chunk_));
1982 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001983 } else if (expected.NeedsMap()) {
1984 // If we need a map later and have a Smi -> deopt.
1985 __ testb(reg, Immediate(kSmiTagMask));
1986 DeoptimizeIf(zero, instr->environment());
1987 }
1988
1989 const Register map = kScratchRegister;
1990 if (expected.NeedsMap()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00001991 __ movp(map, FieldOperand(reg, HeapObject::kMapOffset));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001992
1993 if (expected.CanBeUndetectable()) {
1994 // Undetectable -> false.
1995 __ testb(FieldOperand(map, Map::kBitFieldOffset),
1996 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001997 __ j(not_zero, instr->FalseLabel(chunk_));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001998 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00001999 }
2000
2001 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2002 // spec object -> true.
2003 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002004 __ j(above_equal, instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002005 }
2006
2007 if (expected.Contains(ToBooleanStub::STRING)) {
2008 // String value -> false iff empty.
2009 Label not_string;
2010 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE);
2011 __ j(above_equal, &not_string, Label::kNear);
2012 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002013 __ j(not_zero, instr->TrueLabel(chunk_));
2014 __ jmp(instr->FalseLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002015 __ bind(&not_string);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002016 }
2017
danno@chromium.orgc16e8282013-08-12 16:17:40 +00002018 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2019 // Symbol value -> true.
2020 __ CmpInstanceType(map, SYMBOL_TYPE);
2021 __ j(equal, instr->TrueLabel(chunk_));
2022 }
2023
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002024 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2025 // heap number -> false iff +0, -0, or NaN.
2026 Label not_heap_number;
2027 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
2028 __ j(not_equal, &not_heap_number, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002029 XMMRegister xmm_scratch = double_scratch0();
2030 __ xorps(xmm_scratch, xmm_scratch);
2031 __ ucomisd(xmm_scratch, FieldOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002032 __ j(zero, instr->FalseLabel(chunk_));
2033 __ jmp(instr->TrueLabel(chunk_));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002034 __ bind(&not_heap_number);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00002035 }
2036
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002037 if (!expected.IsGeneric()) {
2038 // We've seen something for the first time -> deopt.
2039 // This can only happen if we are not generic already.
2040 DeoptimizeIf(no_condition, instr->environment());
2041 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002042 }
2043 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002044}
2045
2046
ager@chromium.org04921a82011-06-27 13:21:41 +00002047void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002048 if (!IsNextEmittedBlock(block)) {
2049 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00002050 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002051}
2052
2053
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002054void LCodeGen::DoGoto(LGoto* instr) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002055 EmitGoto(instr->block_id());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002056}
2057
2058
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002059inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002060 Condition cond = no_condition;
2061 switch (op) {
2062 case Token::EQ:
2063 case Token::EQ_STRICT:
2064 cond = equal;
2065 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002066 case Token::NE:
2067 case Token::NE_STRICT:
2068 cond = not_equal;
2069 break;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002070 case Token::LT:
2071 cond = is_unsigned ? below : less;
2072 break;
2073 case Token::GT:
2074 cond = is_unsigned ? above : greater;
2075 break;
2076 case Token::LTE:
2077 cond = is_unsigned ? below_equal : less_equal;
2078 break;
2079 case Token::GTE:
2080 cond = is_unsigned ? above_equal : greater_equal;
2081 break;
2082 case Token::IN:
2083 case Token::INSTANCEOF:
2084 default:
2085 UNREACHABLE();
2086 }
2087 return cond;
2088}
2089
2090
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002091void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002092 LOperand* left = instr->left();
2093 LOperand* right = instr->right();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002094 Condition cc = TokenToCondition(instr->op(), instr->is_double());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002095
2096 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2097 // We can statically evaluate the comparison.
2098 double left_val = ToDouble(LConstantOperand::cast(left));
2099 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002100 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2101 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002102 EmitGoto(next_block);
2103 } else {
2104 if (instr->is_double()) {
2105 // Don't base result on EFLAGS when a NaN is involved. Instead
2106 // jump to the false block.
2107 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002108 __ j(parity_even, instr->FalseLabel(chunk_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002109 } else {
2110 int32_t value;
2111 if (right->IsConstantOperand()) {
2112 value = ToInteger32(LConstantOperand::cast(right));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002113 if (instr->hydrogen_value()->representation().IsSmi()) {
2114 __ Cmp(ToRegister(left), Smi::FromInt(value));
2115 } else {
2116 __ cmpl(ToRegister(left), Immediate(value));
2117 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002118 } else if (left->IsConstantOperand()) {
2119 value = ToInteger32(LConstantOperand::cast(left));
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002120 if (instr->hydrogen_value()->representation().IsSmi()) {
2121 if (right->IsRegister()) {
2122 __ Cmp(ToRegister(right), Smi::FromInt(value));
2123 } else {
2124 __ Cmp(ToOperand(right), Smi::FromInt(value));
2125 }
2126 } else if (right->IsRegister()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002127 __ cmpl(ToRegister(right), Immediate(value));
2128 } else {
2129 __ cmpl(ToOperand(right), Immediate(value));
2130 }
2131 // We transposed the operands. Reverse the condition.
2132 cc = ReverseCondition(cc);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00002133 } else if (instr->hydrogen_value()->representation().IsSmi()) {
2134 if (right->IsRegister()) {
2135 __ cmpq(ToRegister(left), ToRegister(right));
2136 } else {
2137 __ cmpq(ToRegister(left), ToOperand(right));
2138 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002139 } else {
2140 if (right->IsRegister()) {
2141 __ cmpl(ToRegister(left), ToRegister(right));
2142 } else {
2143 __ cmpl(ToRegister(left), ToOperand(right));
2144 }
2145 }
2146 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002147 EmitBranch(instr, cc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002148 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002149}
2150
2151
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00002152void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002153 Register left = ToRegister(instr->left());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002154
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002155 if (instr->right()->IsConstantOperand()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002156 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002157 __ Cmp(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002158 } else {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002159 Register right = ToRegister(instr->right());
2160 __ cmpq(left, right);
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00002161 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002162 EmitBranch(instr, equal);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002163}
2164
2165
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00002166void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2167 if (instr->hydrogen()->representation().IsTagged()) {
2168 Register input_reg = ToRegister(instr->object());
2169 __ Cmp(input_reg, factory()->the_hole_value());
2170 EmitBranch(instr, equal);
2171 return;
2172 }
2173
2174 XMMRegister input_reg = ToDoubleRegister(instr->object());
2175 __ ucomisd(input_reg, input_reg);
2176 EmitFalseBranch(instr, parity_odd);
2177
2178 __ subq(rsp, Immediate(kDoubleSize));
2179 __ movsd(MemOperand(rsp, 0), input_reg);
2180 __ addq(rsp, Immediate(kDoubleSize));
2181
2182 int offset = sizeof(kHoleNanUpper32);
2183 __ cmpl(MemOperand(rsp, -offset), Immediate(kHoleNanUpper32));
2184 EmitBranch(instr, equal);
2185}
2186
2187
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002188void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2189 Representation rep = instr->hydrogen()->value()->representation();
2190 ASSERT(!rep.IsInteger32());
2191
2192 if (rep.IsDouble()) {
2193 XMMRegister value = ToDoubleRegister(instr->value());
2194 XMMRegister xmm_scratch = double_scratch0();
2195 __ xorps(xmm_scratch, xmm_scratch);
2196 __ ucomisd(xmm_scratch, value);
2197 EmitFalseBranch(instr, not_equal);
2198 __ movmskpd(kScratchRegister, value);
2199 __ testl(kScratchRegister, Immediate(1));
2200 EmitBranch(instr, not_zero);
2201 } else {
2202 Register value = ToRegister(instr->value());
2203 Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
2204 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK);
2205 __ cmpl(FieldOperand(value, HeapNumber::kExponentOffset),
2206 Immediate(0x80000000));
2207 EmitFalseBranch(instr, not_equal);
2208 __ cmpl(FieldOperand(value, HeapNumber::kMantissaOffset),
2209 Immediate(0x00000000));
2210 EmitBranch(instr, equal);
2211 }
2212}
2213
2214
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002215Condition LCodeGen::EmitIsObject(Register input,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002216 Label* is_not_object,
2217 Label* is_object) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002218 ASSERT(!input.is(kScratchRegister));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002219
2220 __ JumpIfSmi(input, is_not_object);
2221
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002222 __ CompareRoot(input, Heap::kNullValueRootIndex);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002223 __ j(equal, is_object);
2224
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002225 __ movp(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002226 // Undetectable objects behave like undefined.
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002227 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset),
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002228 Immediate(1 << Map::kIsUndetectable));
2229 __ j(not_zero, is_not_object);
2230
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002231 __ movzxbl(kScratchRegister,
2232 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002233 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002234 __ j(below, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002235 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002236 return below_equal;
2237}
2238
2239
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002240void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002241 Register reg = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002242
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002243 Condition true_cond = EmitIsObject(
2244 reg, instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002245
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002246 EmitBranch(instr, true_cond);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002247}
2248
2249
erikcorry0ad885c2011-11-21 13:51:57 +00002250Condition LCodeGen::EmitIsString(Register input,
2251 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002252 Label* is_not_string,
2253 SmiCheck check_needed = INLINE_SMI_CHECK) {
2254 if (check_needed == INLINE_SMI_CHECK) {
2255 __ JumpIfSmi(input, is_not_string);
2256 }
2257
erikcorry0ad885c2011-11-21 13:51:57 +00002258 Condition cond = masm_->IsObjectStringType(input, temp1, temp1);
2259
2260 return cond;
2261}
2262
2263
2264void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002265 Register reg = ToRegister(instr->value());
2266 Register temp = ToRegister(instr->temp());
erikcorry0ad885c2011-11-21 13:51:57 +00002267
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002268 SmiCheck check_needed =
2269 instr->hydrogen()->value()->IsHeapObject()
2270 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
erikcorry0ad885c2011-11-21 13:51:57 +00002271
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002272 Condition true_cond = EmitIsString(
2273 reg, temp, instr->FalseLabel(chunk_), check_needed);
erikcorry0ad885c2011-11-21 13:51:57 +00002274
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002275 EmitBranch(instr, true_cond);
erikcorry0ad885c2011-11-21 13:51:57 +00002276}
2277
2278
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002279void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002280 Condition is_smi;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002281 if (instr->value()->IsRegister()) {
2282 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002283 is_smi = masm()->CheckSmi(input);
2284 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002285 Operand input = ToOperand(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002286 is_smi = masm()->CheckSmi(input);
2287 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002288 EmitBranch(instr, is_smi);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002289}
2290
2291
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002292void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002293 Register input = ToRegister(instr->value());
2294 Register temp = ToRegister(instr->temp());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002295
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002296 if (!instr->hydrogen()->value()->IsHeapObject()) {
2297 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2298 }
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002299 __ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002300 __ testb(FieldOperand(temp, Map::kBitFieldOffset),
2301 Immediate(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002302 EmitBranch(instr, not_zero);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00002303}
2304
2305
erikcorry0ad885c2011-11-21 13:51:57 +00002306void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002307 ASSERT(ToRegister(instr->context()).is(rsi));
erikcorry0ad885c2011-11-21 13:51:57 +00002308 Token::Value op = instr->op();
erikcorry0ad885c2011-11-21 13:51:57 +00002309
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002310 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
erikcorry0ad885c2011-11-21 13:51:57 +00002311 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2312
2313 Condition condition = TokenToCondition(op, false);
2314 __ testq(rax, rax);
2315
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002316 EmitBranch(instr, condition);
erikcorry0ad885c2011-11-21 13:51:57 +00002317}
2318
2319
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002320static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002321 InstanceType from = instr->from();
2322 InstanceType to = instr->to();
2323 if (from == FIRST_TYPE) return to;
2324 ASSERT(from == to || to == LAST_TYPE);
2325 return from;
2326}
2327
2328
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002329static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002330 InstanceType from = instr->from();
2331 InstanceType to = instr->to();
2332 if (from == to) return equal;
2333 if (to == LAST_TYPE) return above_equal;
2334 if (from == FIRST_TYPE) return below_equal;
2335 UNREACHABLE();
2336 return equal;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002337}
2338
2339
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002340void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002341 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002342
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002343 if (!instr->hydrogen()->value()->IsHeapObject()) {
2344 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2345 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002346
2347 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002348 EmitBranch(instr, BranchCondition(instr->hydrogen()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002349}
2350
2351
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002352void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002353 Register input = ToRegister(instr->value());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002354 Register result = ToRegister(instr->result());
2355
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002356 __ AssertString(input);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002357
2358 __ movl(result, FieldOperand(input, String::kHashFieldOffset));
2359 ASSERT(String::kHashShift >= kSmiTagSize);
2360 __ IndexFromHash(result, result);
2361}
2362
2363
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002364void LCodeGen::DoHasCachedArrayIndexAndBranch(
2365 LHasCachedArrayIndexAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002366 Register input = ToRegister(instr->value());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002367
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002368 __ testl(FieldOperand(input, String::kHashFieldOffset),
2369 Immediate(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002370 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002371}
2372
2373
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002374// Branches to a label or falls through with the answer in the z flag.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002375// Trashes the temp register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002376void LCodeGen::EmitClassOfTest(Label* is_true,
2377 Label* is_false,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002378 Handle<String> class_name,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002379 Register input,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002380 Register temp,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002381 Register temp2) {
2382 ASSERT(!input.is(temp));
2383 ASSERT(!input.is(temp2));
2384 ASSERT(!temp.is(temp2));
2385
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002386 __ JumpIfSmi(input, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002387
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002388 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002389 // Assuming the following assertions, we can use the same compares to test
2390 // for both being a function type and being in the object type range.
2391 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2392 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2393 FIRST_SPEC_OBJECT_TYPE + 1);
2394 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2395 LAST_SPEC_OBJECT_TYPE - 1);
2396 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2397 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp);
2398 __ j(below, is_false);
2399 __ j(equal, is_true);
2400 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE);
2401 __ j(equal, is_true);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002402 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002403 // Faster code path to avoid two compares: subtract lower bound from the
2404 // actual type and do a signed compare with the width of the type range.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002405 __ movp(temp, FieldOperand(input, HeapObject::kMapOffset));
yangguo@chromium.org56454712012-02-16 15:33:53 +00002406 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset));
2407 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2408 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2409 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002410 __ j(above, is_false);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002411 }
2412
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002413 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002414 // Check if the constructor in the map is a function.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002415 __ movp(temp, FieldOperand(temp, Map::kConstructorOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002416
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002417 // Objects with a non-function constructor have class 'Object'.
2418 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002419 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002420 __ j(not_equal, is_true);
2421 } else {
2422 __ j(not_equal, is_false);
2423 }
2424
2425 // temp now contains the constructor function. Grab the
2426 // instance class name from there.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002427 __ movp(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2428 __ movp(temp, FieldOperand(temp,
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002429 SharedFunctionInfo::kInstanceClassNameOffset));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002430 // The class name we are testing against is internalized since it's a literal.
2431 // The name in the constructor is internalized because of the way the context
2432 // is booted. This routine isn't expected to work for random API-created
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002433 // classes and it doesn't have to because you can't access it with natives
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002434 // syntax. Since both sides are internalized it is sufficient to use an
2435 // identity comparison.
2436 ASSERT(class_name->IsInternalizedString());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002437 __ Cmp(temp, class_name);
2438 // End with the answer in the z flag.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002439}
2440
2441
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002442void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002443 Register input = ToRegister(instr->value());
2444 Register temp = ToRegister(instr->temp());
2445 Register temp2 = ToRegister(instr->temp2());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002446 Handle<String> class_name = instr->hydrogen()->class_name();
2447
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002448 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2449 class_name, input, temp, temp2);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002450
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002451 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002452}
2453
2454
2455void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002456 Register reg = ToRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00002457
2458 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002459 EmitBranch(instr, equal);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002460}
2461
2462
2463void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002464 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002465 InstanceofStub stub(InstanceofStub::kNoFlags);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002466 __ push(ToRegister(instr->left()));
2467 __ push(ToRegister(instr->right()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002468 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002469 Label true_value, done;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002470 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002471 __ j(zero, &true_value, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002472 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002473 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002474 __ bind(&true_value);
2475 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2476 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002477}
2478
2479
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002480void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002481 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002482 public:
2483 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2484 LInstanceOfKnownGlobal* instr)
2485 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002486 virtual void Generate() V8_OVERRIDE {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002487 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002488 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002489 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002490 Label* map_check() { return &map_check_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002491 private:
2492 LInstanceOfKnownGlobal* instr_;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002493 Label map_check_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002494 };
2495
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002496 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002497 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002498 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002499
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002500 Label done, false_result;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002501 Register object = ToRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002502
2503 // A Smi is not an instance of anything.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002504 __ JumpIfSmi(object, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002505
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002506 // This is the inlined call site instanceof cache. The two occurences of the
2507 // hole value will be patched to the last map/result pair generated by the
2508 // instanceof stub.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002509 Label cache_miss;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002510 // Use a temp register to avoid memory operands with variable lengths.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002511 Register map = ToRegister(instr->temp());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002512 __ movp(map, FieldOperand(object, HeapObject::kMapOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002513 __ bind(deferred->map_check()); // Label for calculating code patching.
danno@chromium.org41728482013-06-12 22:31:22 +00002514 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002515 __ Move(kScratchRegister, cache_cell, RelocInfo::CELL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002516 __ cmpq(map, Operand(kScratchRegister, 0));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002517 __ j(not_equal, &cache_miss, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002518 // Patched to load either true or false.
2519 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex);
2520#ifdef DEBUG
2521 // Check that the code size between patch label and patch sites is invariant.
2522 Label end_of_patched_code;
2523 __ bind(&end_of_patched_code);
2524 ASSERT(true);
2525#endif
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002526 __ jmp(&done, Label::kNear);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002527
2528 // The inlined call site cache did not match. Check for null and string
2529 // before calling the deferred code.
2530 __ bind(&cache_miss); // Null is not an instance of anything.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002531 __ CompareRoot(object, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002532 __ j(equal, &false_result, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002533
2534 // String values are not instances of anything.
2535 __ JumpIfNotString(object, kScratchRegister, deferred->entry());
2536
2537 __ bind(&false_result);
2538 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
2539
2540 __ bind(deferred->exit());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002541 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002542}
2543
2544
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002545void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2546 Label* map_check) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002547 {
2548 PushSafepointRegistersScope scope(this);
2549 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>(
2550 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck);
2551 InstanceofStub stub(flags);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002552
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002553 __ push(ToRegister(instr->value()));
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002554 __ Push(instr->function());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002555
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002556 static const int kAdditionalDelta = 10;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002557 int delta =
2558 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002559 ASSERT(delta >= 0);
2560 __ push_imm32(delta);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002561
2562 // We are pushing three values on the stack but recording a
2563 // safepoint with two arguments because stub is going to
2564 // remove the third argument from the stack before jumping
2565 // to instanceof builtin on the slow path.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002566 CallCodeGeneric(stub.GetCode(isolate()),
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002567 RelocInfo::CODE_TARGET,
2568 instr,
2569 RECORD_SAFEPOINT_WITH_REGISTERS,
2570 2);
2571 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check));
danno@chromium.org1044a4d2012-04-30 12:34:39 +00002572 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00002573 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002574 // Move result to a register that survives the end of the
2575 // PushSafepointRegisterScope.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002576 __ movp(kScratchRegister, rax);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002577 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002578 __ testq(kScratchRegister, kScratchRegister);
2579 Label load_false;
2580 Label done;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002581 __ j(not_zero, &load_false, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002582 __ LoadRoot(rax, Heap::kTrueValueRootIndex);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002583 __ jmp(&done, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002584 __ bind(&load_false);
2585 __ LoadRoot(rax, Heap::kFalseValueRootIndex);
2586 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002587}
2588
2589
2590void LCodeGen::DoCmpT(LCmpT* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002591 ASSERT(ToRegister(instr->context()).is(rsi));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002592 Token::Value op = instr->op();
2593
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002594 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002595 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2596
2597 Condition condition = TokenToCondition(op, false);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002598 Label true_value, done;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002599 __ testq(rax, rax);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002600 __ j(condition, &true_value, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002601 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002602 __ jmp(&done, Label::kNear);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002603 __ bind(&true_value);
2604 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
2605 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002606}
2607
2608
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002609void LCodeGen::DoReturn(LReturn* instr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002610 if (FLAG_trace && info()->IsOptimizing()) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002611 // Preserve the return value on the stack and rely on the runtime call
2612 // to return the value in the same register. We're leaving the code
2613 // managed by the register allocator and tearing down the frame, it's
2614 // safe to write to the context register.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002615 __ push(rax);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002616 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002617 __ CallRuntime(Runtime::kTraceExit, 1);
2618 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002619 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002620 RestoreCallerDoubles();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002621 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002622 int no_frame_start = -1;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002623 if (NeedsEagerFrame()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002624 __ movp(rsp, rbp);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002625 __ pop(rbp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002626 no_frame_start = masm_->pc_offset();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002627 }
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002628 if (instr->has_constant_parameter_count()) {
2629 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize,
2630 rcx);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002631 } else {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002632 Register reg = ToRegister(instr->parameter_count());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002633 // The argument count parameter is a smi
2634 __ SmiToInteger32(reg, reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002635 Register return_addr_reg = reg.is(rcx) ? rbx : rcx;
danno@chromium.org59400602013-08-13 17:09:37 +00002636 __ PopReturnAddressTo(return_addr_reg);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00002637 __ shl(reg, Immediate(kPointerSizeLog2));
2638 __ addq(rsp, reg);
2639 __ jmp(return_addr_reg);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002640 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002641 if (no_frame_start != -1) {
2642 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2643 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002644}
2645
2646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002647void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002648 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002649 __ LoadGlobalCell(result, instr->hydrogen()->cell().handle());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002650 if (instr->hydrogen()->RequiresHoleCheck()) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002651 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2652 DeoptimizeIf(equal, instr->environment());
2653 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002654}
2655
2656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002657void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002658 ASSERT(ToRegister(instr->context()).is(rsi));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002659 ASSERT(ToRegister(instr->global_object()).is(rax));
2660 ASSERT(ToRegister(instr->result()).is(rax));
2661
2662 __ Move(rcx, instr->name());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002663 ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
2664 Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode);
2665 CallCode(ic, RelocInfo::CODE_TARGET, instr);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002666}
2667
2668
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002669void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002670 Register value = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002671 Handle<Cell> cell_handle = instr->hydrogen()->cell().handle();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002672
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002673 // If the cell we are storing to contains the hole it could have
2674 // been deleted from the property dictionary. In that case, we need
2675 // to update the property details in the property dictionary to mark
2676 // it as no longer deleted. We deoptimize in that case.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002677 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002678 // We have a temp because CompareRoot might clobber kScratchRegister.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002679 Register cell = ToRegister(instr->temp());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002680 ASSERT(!value.is(cell));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002681 __ Move(cell, cell_handle, RelocInfo::CELL);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002682 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002683 DeoptimizeIf(equal, instr->environment());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002684 // Store the value.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002685 __ movp(Operand(cell, 0), value);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002686 } else {
2687 // Store the value.
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002688 __ Move(kScratchRegister, cell_handle, RelocInfo::CELL);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002689 __ movp(Operand(kScratchRegister, 0), value);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002690 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002691 // Cells are always rescanned, so no write barrier here.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002692}
2693
2694
2695void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002696 Register context = ToRegister(instr->context());
2697 Register result = ToRegister(instr->result());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002698 __ movp(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002699 if (instr->hydrogen()->RequiresHoleCheck()) {
2700 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002701 if (instr->hydrogen()->DeoptimizesOnHole()) {
2702 DeoptimizeIf(equal, instr->environment());
2703 } else {
2704 Label is_not_hole;
2705 __ j(not_equal, &is_not_hole, Label::kNear);
2706 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2707 __ bind(&is_not_hole);
2708 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002709 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002710}
2711
2712
2713void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2714 Register context = ToRegister(instr->context());
2715 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002716
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002717 Operand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002718
2719 Label skip_assignment;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002720 if (instr->hydrogen()->RequiresHoleCheck()) {
2721 __ CompareRoot(target, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002722 if (instr->hydrogen()->DeoptimizesOnHole()) {
2723 DeoptimizeIf(equal, instr->environment());
2724 } else {
2725 __ j(not_equal, &skip_assignment);
2726 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002727 }
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002728 __ movp(target, value);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002730 if (instr->hydrogen()->NeedsWriteBarrier()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002731 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002732 instr->hydrogen()->value()->IsHeapObject()
2733 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002734 int offset = Context::SlotOffset(instr->slot_index());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002735 Register scratch = ToRegister(instr->temp());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002736 __ RecordWriteContextSlot(context,
2737 offset,
2738 value,
2739 scratch,
2740 kSaveFPRegs,
2741 EMIT_REMEMBERED_SET,
2742 check_needed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002743 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002744
2745 __ bind(&skip_assignment);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002746}
2747
2748
2749void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002750 HObjectAccess access = instr->hydrogen()->access();
2751 int offset = access.offset();
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002752
2753 if (access.IsExternalMemory()) {
2754 Register result = ToRegister(instr->result());
2755 if (instr->object()->IsConstantOperand()) {
2756 ASSERT(result.is(rax));
2757 __ load_rax(ToExternalReference(LConstantOperand::cast(instr->object())));
2758 } else {
2759 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002760 __ Load(result, MemOperand(object, offset), access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002761 }
2762 return;
2763 }
2764
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002765 Register object = ToRegister(instr->object());
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00002766 if (instr->hydrogen()->representation().IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002767 XMMRegister result = ToDoubleRegister(instr->result());
2768 __ movsd(result, FieldOperand(object, offset));
2769 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002770 }
2771
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002772 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002773 if (!access.IsInobject()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002774 __ movp(result, FieldOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002775 object = result;
ager@chromium.org378b34e2011-01-28 08:04:38 +00002776 }
jkummerow@chromium.org113035e2013-12-13 15:13:40 +00002777
2778 Representation representation = access.representation();
2779 if (representation.IsSmi() &&
2780 instr->hydrogen()->representation().IsInteger32()) {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00002781#ifdef DEBUG
2782 Register scratch = kScratchRegister;
2783 __ Load(scratch, FieldOperand(object, offset), representation);
2784 __ AssertSmi(scratch);
2785#endif
2786
jkummerow@chromium.org113035e2013-12-13 15:13:40 +00002787 // Read int value directly from upper half of the smi.
2788 STATIC_ASSERT(kSmiTag == 0);
2789 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
2790 offset += kPointerSize / 2;
2791 representation = Representation::Integer32();
2792 }
2793 __ Load(result, FieldOperand(object, offset), representation);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002794}
2795
2796
2797void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002798 ASSERT(ToRegister(instr->context()).is(rsi));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002799 ASSERT(ToRegister(instr->object()).is(rax));
2800 ASSERT(ToRegister(instr->result()).is(rax));
2801
2802 __ Move(rcx, instr->name());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002803 Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002804 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002805}
2806
2807
2808void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002809 Register function = ToRegister(instr->function());
2810 Register result = ToRegister(instr->result());
2811
2812 // Check that the function really is a function.
2813 __ CmpObjectType(function, JS_FUNCTION_TYPE, result);
2814 DeoptimizeIf(not_equal, instr->environment());
2815
2816 // Check whether the function has an instance prototype.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002817 Label non_instance;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002818 __ testb(FieldOperand(result, Map::kBitFieldOffset),
2819 Immediate(1 << Map::kHasNonInstancePrototype));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002820 __ j(not_zero, &non_instance, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002821
2822 // Get the prototype or initial map from the function.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002823 __ movp(result,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002824 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2825
2826 // Check that the function has a prototype or an initial map.
2827 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
2828 DeoptimizeIf(equal, instr->environment());
2829
2830 // If the function does not have an initial map, we're done.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002831 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002832 __ CmpObjectType(result, MAP_TYPE, kScratchRegister);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002833 __ j(not_equal, &done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002834
2835 // Get the prototype from the initial map.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002836 __ movp(result, FieldOperand(result, Map::kPrototypeOffset));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002837 __ jmp(&done, Label::kNear);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002838
2839 // Non-instance prototype: Fetch prototype from constructor field
2840 // in the function's map.
2841 __ bind(&non_instance);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002842 __ movp(result, FieldOperand(result, Map::kConstructorOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002843
2844 // All done.
2845 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002846}
2847
2848
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002849void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
2850 Register result = ToRegister(instr->result());
2851 __ LoadRoot(result, instr->index());
2852}
2853
2854
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002855void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002856 Register arguments = ToRegister(instr->arguments());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002857 Register result = ToRegister(instr->result());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002858
2859 if (instr->length()->IsConstantOperand() &&
2860 instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002861 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2862 int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length()));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002863 StackArgumentsAccessor args(arguments, const_length,
2864 ARGUMENTS_DONT_CONTAIN_RECEIVER);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002865 __ movp(result, args.GetArgumentOperand(const_index));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002866 } else {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002867 Register length = ToRegister(instr->length());
2868 // There are two words between the frame pointer and the last argument.
2869 // Subtracting from length accounts for one of them add one more.
2870 if (instr->index()->IsRegister()) {
2871 __ subl(length, ToRegister(instr->index()));
2872 } else {
2873 __ subl(length, ToOperand(instr->index()));
2874 }
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002875 StackArgumentsAccessor args(arguments, length,
2876 ARGUMENTS_DONT_CONTAIN_RECEIVER);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00002877 __ movp(result, args.GetArgumentOperand(0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002878 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002879}
2880
2881
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002882void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
2883 ElementsKind elements_kind = instr->elements_kind();
2884 LOperand* key = instr->key();
2885 if (!key->IsConstantOperand()) {
2886 Register key_reg = ToRegister(key);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002887 // Even though the HLoad/StoreKeyed (in this case) instructions force
2888 // the input representation for the key to be an integer, the input
2889 // gets replaced during bound check elimination with the index argument
2890 // to the bounds check, which can be tagged, so that case must be
2891 // handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002892 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002893 // Sign extend key because it could be a 32 bit negative value
2894 // and the dehoisted address computation happens in 64 bits
2895 __ movsxlq(key_reg, key_reg);
2896 }
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002897 }
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002898 int base_offset = instr->is_fixed_typed_array()
2899 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag
2900 : 0;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002901 Operand operand(BuildFastArrayOperand(
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002902 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002903 key,
2904 elements_kind,
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002905 base_offset,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002906 instr->additional_index()));
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00002907
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002908 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002909 elements_kind == FLOAT32_ELEMENTS) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002910 XMMRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002911 __ movss(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002912 __ cvtss2sd(result, result);
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002913 } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002914 elements_kind == FLOAT64_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002915 __ movsd(ToDoubleRegister(instr->result()), operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002916 } else {
2917 Register result(ToRegister(instr->result()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002918 switch (elements_kind) {
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002919 case EXTERNAL_INT8_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002920 case INT8_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002921 __ movsxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002922 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002923 case EXTERNAL_UINT8_ELEMENTS:
2924 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002925 case UINT8_ELEMENTS:
2926 case UINT8_CLAMPED_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002927 __ movzxbq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002928 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002929 case EXTERNAL_INT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002930 case INT16_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002931 __ movsxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002932 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002933 case EXTERNAL_UINT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002934 case UINT16_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002935 __ movzxwq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002936 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002937 case EXTERNAL_INT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002938 case INT32_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002939 __ movsxlq(result, operand);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002940 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002941 case EXTERNAL_UINT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002942 case UINT32_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002943 __ movl(result, operand);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002944 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2945 __ testl(result, result);
2946 DeoptimizeIf(negative, instr->environment());
2947 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002948 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00002949 case EXTERNAL_FLOAT32_ELEMENTS:
2950 case EXTERNAL_FLOAT64_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00002951 case FLOAT32_ELEMENTS:
2952 case FLOAT64_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002953 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002954 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002955 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002956 case FAST_HOLEY_ELEMENTS:
2957 case FAST_HOLEY_SMI_ELEMENTS:
2958 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002959 case DICTIONARY_ELEMENTS:
2960 case NON_STRICT_ARGUMENTS_ELEMENTS:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002961 UNREACHABLE();
2962 break;
2963 }
2964 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002965}
2966
2967
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002968void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
2969 XMMRegister result(ToDoubleRegister(instr->result()));
2970 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002971 if (!key->IsConstantOperand()) {
2972 Register key_reg = ToRegister(key);
2973 // Even though the HLoad/StoreKeyed instructions force the input
2974 // representation for the key to be an integer, the input gets replaced
2975 // during bound check elimination with the index argument to the bounds
2976 // check, which can be tagged, so that case must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002977 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002978 // Sign extend key because it could be a 32 bit negative value
2979 // and the dehoisted address computation happens in 64 bits
2980 __ movsxlq(key_reg, key_reg);
2981 }
2982 }
2983
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002984 if (instr->hydrogen()->RequiresHoleCheck()) {
2985 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag +
2986 sizeof(kHoleNanLower32);
2987 Operand hole_check_operand = BuildFastArrayOperand(
2988 instr->elements(),
2989 key,
2990 FAST_DOUBLE_ELEMENTS,
2991 offset,
2992 instr->additional_index());
2993 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32));
2994 DeoptimizeIf(equal, instr->environment());
2995 }
2996
2997 Operand double_load_operand = BuildFastArrayOperand(
2998 instr->elements(),
2999 key,
3000 FAST_DOUBLE_ELEMENTS,
3001 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
3002 instr->additional_index());
3003 __ movsd(result, double_load_operand);
3004}
3005
3006
3007void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003008 HLoadKeyed* hinstr = instr->hydrogen();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003009 Register result = ToRegister(instr->result());
3010 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003011 if (!key->IsConstantOperand()) {
3012 Register key_reg = ToRegister(key);
3013 // Even though the HLoad/StoreKeyedFastElement instructions force
3014 // the input representation for the key to be an integer, the input
3015 // gets replaced during bound check elimination with the index
3016 // argument to the bounds check, which can be tagged, so that
3017 // case must be handled here, too.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003018 if (hinstr->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003019 // Sign extend key because it could be a 32 bit negative value
3020 // and the dehoisted address computation happens in 64 bits
3021 __ movsxlq(key_reg, key_reg);
3022 }
3023 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003024
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003025 bool requires_hole_check = hinstr->RequiresHoleCheck();
3026 int offset = FixedArray::kHeaderSize - kHeapObjectTag;
3027 Representation representation = hinstr->representation();
3028
3029 if (representation.IsInteger32() &&
3030 hinstr->elements_kind() == FAST_SMI_ELEMENTS) {
3031 ASSERT(!requires_hole_check);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003032#ifdef DEBUG
3033 Register scratch = kScratchRegister;
3034 __ Load(scratch,
3035 BuildFastArrayOperand(instr->elements(),
3036 key,
3037 FAST_ELEMENTS,
3038 offset,
3039 instr->additional_index()),
3040 Representation::Smi());
3041 __ AssertSmi(scratch);
3042#endif
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003043 // Read int value directly from upper half of the smi.
3044 STATIC_ASSERT(kSmiTag == 0);
3045 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
3046 offset += kPointerSize / 2;
3047 }
3048
3049 __ Load(result,
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003050 BuildFastArrayOperand(instr->elements(),
3051 key,
3052 FAST_ELEMENTS,
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003053 offset,
3054 instr->additional_index()),
3055 representation);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003056
3057 // Check for the hole value.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003058 if (requires_hole_check) {
3059 if (IsFastSmiElementsKind(hinstr->elements_kind())) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003060 Condition smi = __ CheckSmi(result);
3061 DeoptimizeIf(NegateCondition(smi), instr->environment());
3062 } else {
3063 __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
3064 DeoptimizeIf(equal, instr->environment());
3065 }
3066 }
3067}
3068
3069
3070void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003071 if (instr->is_typed_elements()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003072 DoLoadKeyedExternalArray(instr);
3073 } else if (instr->hydrogen()->representation().IsDouble()) {
3074 DoLoadKeyedFixedDoubleArray(instr);
3075 } else {
3076 DoLoadKeyedFixedArray(instr);
3077 }
3078}
3079
3080
3081Operand LCodeGen::BuildFastArrayOperand(
3082 LOperand* elements_pointer,
3083 LOperand* key,
3084 ElementsKind elements_kind,
3085 uint32_t offset,
3086 uint32_t additional_index) {
3087 Register elements_pointer_reg = ToRegister(elements_pointer);
3088 int shift_size = ElementsKindToShiftSize(elements_kind);
3089 if (key->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003090 int32_t constant_value = ToInteger32(LConstantOperand::cast(key));
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003091 if (constant_value & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003092 Abort(kArrayIndexConstantValueTooBig);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00003093 }
3094 return Operand(elements_pointer_reg,
3095 ((constant_value + additional_index) << shift_size)
3096 + offset);
3097 } else {
3098 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size);
3099 return Operand(elements_pointer_reg,
3100 ToRegister(key),
3101 scale_factor,
3102 offset + (additional_index << shift_size));
3103 }
3104}
3105
3106
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003107void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003108 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003109 ASSERT(ToRegister(instr->object()).is(rdx));
3110 ASSERT(ToRegister(instr->key()).is(rax));
3111
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003112 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003113 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003114}
3115
3116
3117void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003118 Register result = ToRegister(instr->result());
3119
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003120 if (instr->hydrogen()->from_inlined()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003121 __ lea(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003122 } else {
3123 // Check for arguments adapter frame.
3124 Label done, adapted;
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003125 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003126 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
3127 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
3128 __ j(equal, &adapted, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003129
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003130 // No arguments adaptor frame.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003131 __ movp(result, rbp);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003132 __ jmp(&done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003133
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003134 // Arguments adaptor frame present.
3135 __ bind(&adapted);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003136 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003137
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003138 // Result is the frame pointer for the frame if not adapted and for the real
3139 // frame below the adaptor frame if adapted.
3140 __ bind(&done);
3141 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003142}
3143
3144
3145void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003146 Register result = ToRegister(instr->result());
3147
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003148 Label done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003149
3150 // If no arguments adaptor frame the number of arguments is fixed.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003151 if (instr->elements()->IsRegister()) {
3152 __ cmpq(rbp, ToRegister(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003153 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003154 __ cmpq(rbp, ToOperand(instr->elements()));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003155 }
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003156 __ movl(result, Immediate(scope()->num_parameters()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003157 __ j(equal, &done, Label::kNear);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003158
3159 // Arguments adaptor frame present. Get argument length from there.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003160 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003161 __ SmiToInteger32(result,
3162 Operand(result,
3163 ArgumentsAdaptorFrameConstants::kLengthOffset));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003164
3165 // Argument length is in result register.
3166 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003167}
3168
3169
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003170void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003171 Register receiver = ToRegister(instr->receiver());
3172 Register function = ToRegister(instr->function());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003173
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003174 // If the receiver is null or undefined, we have to pass the global
3175 // object as a receiver to normal functions. Values have to be
3176 // passed unchanged to builtins and strict-mode functions.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003177 Label global_object, receiver_ok;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003178 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003179
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003180 if (!instr->hydrogen()->known_function()) {
3181 // Do not transform the receiver to object for strict mode
3182 // functions.
3183 __ movp(kScratchRegister,
3184 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset));
3185 __ testb(FieldOperand(kScratchRegister,
3186 SharedFunctionInfo::kStrictModeByteOffset),
3187 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte));
3188 __ j(not_equal, &receiver_ok, dist);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003189
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003190 // Do not transform the receiver to object for builtins.
3191 __ testb(FieldOperand(kScratchRegister,
3192 SharedFunctionInfo::kNativeByteOffset),
3193 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte));
3194 __ j(not_equal, &receiver_ok, dist);
3195 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003196
3197 // Normal function. Replace undefined or null with global receiver.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003198 __ CompareRoot(receiver, Heap::kNullValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003199 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003200 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003201 __ j(equal, &global_object, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003202
3203 // The receiver should be a JS object.
3204 Condition is_smi = __ CheckSmi(receiver);
3205 DeoptimizeIf(is_smi, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003206 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003207 DeoptimizeIf(below, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003208
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003209 __ jmp(&receiver_ok, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003210 __ bind(&global_object);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003211 __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset));
3212 __ movp(receiver,
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003213 Operand(receiver,
3214 Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003215 __ movp(receiver,
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003216 FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset));
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003217
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003218 __ bind(&receiver_ok);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00003219}
3220
3221
3222void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3223 Register receiver = ToRegister(instr->receiver());
3224 Register function = ToRegister(instr->function());
3225 Register length = ToRegister(instr->length());
3226 Register elements = ToRegister(instr->elements());
3227 ASSERT(receiver.is(rax)); // Used for parameter count.
3228 ASSERT(function.is(rdi)); // Required by InvokeFunction.
3229 ASSERT(ToRegister(instr->result()).is(rax));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003230
3231 // Copy the arguments to this function possibly from the
3232 // adaptor frame below it.
3233 const uint32_t kArgumentsLimit = 1 * KB;
3234 __ cmpq(length, Immediate(kArgumentsLimit));
3235 DeoptimizeIf(above, instr->environment());
3236
3237 __ push(receiver);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003238 __ movp(receiver, length);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003239
3240 // Loop through the arguments pushing them onto the execution
3241 // stack.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003242 Label invoke, loop;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003243 // length is a small non-negative integer, due to the test above.
3244 __ testl(length, length);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003245 __ j(zero, &invoke, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003246 __ bind(&loop);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003247 StackArgumentsAccessor args(elements, length,
3248 ARGUMENTS_DONT_CONTAIN_RECEIVER);
3249 __ push(args.GetArgumentOperand(0));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003250 __ decl(length);
3251 __ j(not_zero, &loop);
3252
3253 // Invoke the function.
3254 __ bind(&invoke);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00003255 ASSERT(instr->HasPointerMap());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003256 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00003257 SafepointGenerator safepoint_generator(
3258 this, pointers, Safepoint::kLazyDeopt);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003259 ParameterCount actual(rax);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003260 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003261}
3262
3263
3264void LCodeGen::DoPushArgument(LPushArgument* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003265 LOperand* argument = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00003266 EmitPushTaggedOperand(argument);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003267}
3268
3269
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003270void LCodeGen::DoDrop(LDrop* instr) {
3271 __ Drop(instr->count());
3272}
3273
3274
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003275void LCodeGen::DoThisFunction(LThisFunction* instr) {
3276 Register result = ToRegister(instr->result());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003277 __ movp(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003278}
3279
3280
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003281void LCodeGen::DoContext(LContext* instr) {
3282 Register result = ToRegister(instr->result());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003283 if (info()->IsOptimizing()) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003284 __ movp(result, Operand(rbp, StandardFrameConstants::kContextOffset));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003285 } else {
3286 // If there is no frame, the context must be in rsi.
3287 ASSERT(result.is(rsi));
3288 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003289}
3290
3291
yangguo@chromium.org56454712012-02-16 15:33:53 +00003292void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003293 ASSERT(ToRegister(instr->context()).is(rsi));
yangguo@chromium.org56454712012-02-16 15:33:53 +00003294 __ push(rsi); // The context is the first argument.
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003295 __ Push(instr->hydrogen()->pairs());
yangguo@chromium.org56454712012-02-16 15:33:53 +00003296 __ Push(Smi::FromInt(instr->hydrogen()->flags()));
3297 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3298}
3299
3300
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003301void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003302 int formal_parameter_count,
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003303 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00003304 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003305 RDIState rdi_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003306 bool dont_adapt_arguments =
3307 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3308 bool can_invoke_directly =
3309 dont_adapt_arguments || formal_parameter_count == arity;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003310
3311 LPointerMap* pointers = instr->pointer_map();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003312
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003313 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003314 if (rdi_state == RDI_UNINITIALIZED) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00003315 __ Move(rdi, function);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003316 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003317
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003318 // Change context.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003319 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003320
3321 // Set rax to arguments count if adaption is not needed. Assumes that rax
3322 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003323 if (dont_adapt_arguments) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003324 __ Set(rax, arity);
3325 }
3326
3327 // Invoke function.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003328 if (function.is_identical_to(info()->closure())) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003329 __ CallSelf();
3330 } else {
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003331 __ Call(FieldOperand(rdi, JSFunction::kCodeEntryOffset));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003332 }
3333
3334 // Set up deoptimization.
3335 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0);
3336 } else {
3337 // We need to adapt arguments.
3338 SafepointGenerator generator(
3339 this, pointers, Safepoint::kLazyDeopt);
3340 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003341 ParameterCount expected(formal_parameter_count);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003342 __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003343 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003344}
3345
3346
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003347void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003348 ASSERT(ToRegister(instr->result()).is(rax));
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003349
3350 LPointerMap* pointers = instr->pointer_map();
3351 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3352
3353 if (instr->target()->IsConstantOperand()) {
3354 LConstantOperand* target = LConstantOperand::cast(instr->target());
3355 Handle<Code> code = Handle<Code>::cast(ToHandle(target));
3356 generator.BeforeCall(__ CallSize(code));
3357 __ call(code, RelocInfo::CODE_TARGET);
3358 } else {
3359 ASSERT(instr->target()->IsRegister());
3360 Register target = ToRegister(instr->target());
3361 generator.BeforeCall(__ CallSize(target));
3362 __ addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
3363 __ call(target);
3364 }
3365 generator.AfterCall();
3366}
3367
3368
3369void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
3370 ASSERT(ToRegister(instr->function()).is(rdi));
3371 ASSERT(ToRegister(instr->result()).is(rax));
3372
3373 if (instr->hydrogen()->pass_argument_count()) {
3374 __ Set(rax, instr->arity());
3375 }
3376
3377 // Change context.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003378 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003379
3380 LPointerMap* pointers = instr->pointer_map();
3381 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3382
3383 bool is_self_call = false;
3384 if (instr->hydrogen()->function()->IsConstant()) {
3385 Handle<JSFunction> jsfun = Handle<JSFunction>::null();
3386 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function());
3387 jsfun = Handle<JSFunction>::cast(fun_const->handle(isolate()));
3388 is_self_call = jsfun.is_identical_to(info()->closure());
3389 }
3390
3391 if (is_self_call) {
3392 __ CallSelf();
3393 } else {
3394 Operand target = FieldOperand(rdi, JSFunction::kCodeEntryOffset);
3395 generator.BeforeCall(__ CallSize(target));
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003396 __ Call(target);
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003397 }
3398 generator.AfterCall();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003399}
3400
3401
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003402void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003403 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003404 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
3405 Heap::kHeapNumberMapRootIndex);
3406 DeoptimizeIf(not_equal, instr->environment());
3407
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003408 Label slow, allocated, done;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003409 Register tmp = input_reg.is(rax) ? rcx : rax;
3410 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx;
3411
3412 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003413 PushSafepointRegistersScope scope(this);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003414
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003415 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset));
3416 // Check the sign of the argument. If the argument is positive, just
3417 // return it. We do not need to patch the stack since |input| and
3418 // |result| are the same register and |input| will be restored
3419 // unchanged by popping safepoint registers.
3420 __ testl(tmp, Immediate(HeapNumber::kSignMask));
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003421 __ j(zero, &done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003422
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003423 __ AllocateHeapNumber(tmp, tmp2, &slow);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003424 __ jmp(&allocated, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003425
3426 // Slow case: Call the runtime system to do the number allocation.
3427 __ bind(&slow);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003428 CallRuntimeFromDeferred(
3429 Runtime::kAllocateHeapNumber, 0, instr, instr->context());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003430 // Set the pointer to the new heap number in tmp.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003431 if (!tmp.is(rax)) __ movp(tmp, rax);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003432 // Restore input_reg after call to runtime.
3433 __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
3434
3435 __ bind(&allocated);
machenbach@chromium.orgbb8234d2014-02-10 09:01:23 +00003436 __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003437 __ shl(tmp2, Immediate(1));
3438 __ shr(tmp2, Immediate(1));
machenbach@chromium.orgbb8234d2014-02-10 09:01:23 +00003439 __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003440 __ StoreToSafepointRegisterSlot(input_reg, tmp);
3441
3442 __ bind(&done);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003443}
3444
3445
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003446void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003447 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003448 __ testl(input_reg, input_reg);
3449 Label is_positive;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003450 __ j(not_sign, &is_positive, Label::kNear);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003451 __ negl(input_reg); // Sets flags.
3452 DeoptimizeIf(negative, instr->environment());
3453 __ bind(&is_positive);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003454}
3455
3456
danno@chromium.org59400602013-08-13 17:09:37 +00003457void LCodeGen::EmitSmiMathAbs(LMathAbs* instr) {
3458 Register input_reg = ToRegister(instr->value());
3459 __ testq(input_reg, input_reg);
3460 Label is_positive;
3461 __ j(not_sign, &is_positive, Label::kNear);
3462 __ neg(input_reg); // Sets flags.
3463 DeoptimizeIf(negative, instr->environment());
3464 __ bind(&is_positive);
3465}
3466
3467
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003468void LCodeGen::DoMathAbs(LMathAbs* instr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003469 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003470 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003471 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003472 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003473 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003474 virtual void Generate() V8_OVERRIDE {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003475 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3476 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003477 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003478 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003479 LMathAbs* instr_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003480 };
3481
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003482 ASSERT(instr->value()->Equals(instr->result()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003483 Representation r = instr->hydrogen()->value()->representation();
3484
3485 if (r.IsDouble()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003486 XMMRegister scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003487 XMMRegister input_reg = ToDoubleRegister(instr->value());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003488 __ xorps(scratch, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003489 __ subsd(scratch, input_reg);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00003490 __ andps(input_reg, scratch);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003491 } else if (r.IsInteger32()) {
3492 EmitIntegerMathAbs(instr);
danno@chromium.org59400602013-08-13 17:09:37 +00003493 } else if (r.IsSmi()) {
3494 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003495 } else { // Tagged case.
3496 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003497 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003498 Register input_reg = ToRegister(instr->value());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003499 // Smi check.
3500 __ JumpIfNotSmi(input_reg, deferred->entry());
danno@chromium.org59400602013-08-13 17:09:37 +00003501 EmitSmiMathAbs(instr);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003502 __ bind(deferred->exit());
3503 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003504}
3505
3506
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003507void LCodeGen::DoMathFloor(LMathFloor* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003508 XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003509 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003510 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003511
danno@chromium.org160a7b02011-04-18 15:51:38 +00003512 if (CpuFeatures::IsSupported(SSE4_1)) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003513 CpuFeatureScope scope(masm(), SSE4_1);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003514 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3515 // Deoptimize if minus zero.
3516 __ movq(output_reg, input_reg);
3517 __ subq(output_reg, Immediate(1));
3518 DeoptimizeIf(overflow, instr->environment());
3519 }
3520 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
3521 __ cvttsd2si(output_reg, xmm_scratch);
3522 __ cmpl(output_reg, Immediate(0x80000000));
3523 DeoptimizeIf(equal, instr->environment());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003524 } else {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003525 Label negative_sign, done;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003526 // Deoptimize on unordered.
danno@chromium.org160a7b02011-04-18 15:51:38 +00003527 __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
3528 __ ucomisd(input_reg, xmm_scratch);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003529 DeoptimizeIf(parity_even, instr->environment());
3530 __ j(below, &negative_sign, Label::kNear);
3531
danno@chromium.org160a7b02011-04-18 15:51:38 +00003532 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003533 // Check for negative zero.
3534 Label positive_sign;
3535 __ j(above, &positive_sign, Label::kNear);
3536 __ movmskpd(output_reg, input_reg);
3537 __ testq(output_reg, Immediate(1));
3538 DeoptimizeIf(not_zero, instr->environment());
3539 __ Set(output_reg, 0);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003540 __ jmp(&done, Label::kNear);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00003541 __ bind(&positive_sign);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003542 }
3543
3544 // Use truncating instruction (OK because input is positive).
3545 __ cvttsd2si(output_reg, input_reg);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003546 // Overflow is signalled with minint.
3547 __ cmpl(output_reg, Immediate(0x80000000));
3548 DeoptimizeIf(equal, instr->environment());
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003549 __ jmp(&done, Label::kNear);
3550
3551 // Non-zero negative reaches here.
3552 __ bind(&negative_sign);
3553 // Truncate, then compare and compensate.
3554 __ cvttsd2si(output_reg, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003555 __ Cvtlsi2sd(xmm_scratch, output_reg);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003556 __ ucomisd(input_reg, xmm_scratch);
3557 __ j(equal, &done, Label::kNear);
3558 __ subl(output_reg, Immediate(1));
3559 DeoptimizeIf(overflow, instr->environment());
3560
3561 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003562 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003563}
3564
3565
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003566void LCodeGen::DoMathRound(LMathRound* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003567 const XMMRegister xmm_scratch = double_scratch0();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003568 Register output_reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003569 XMMRegister input_reg = ToDoubleRegister(instr->value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003570 static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
3571 static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003572
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003573 Label done, round_to_zero, below_one_half, do_not_compensate, restore;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003574 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003575 __ movq(kScratchRegister, one_half);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003576 __ movq(xmm_scratch, kScratchRegister);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003577 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003578 __ j(above, &below_one_half, Label::kNear);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003579
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003580 // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
3581 __ addsd(xmm_scratch, input_reg);
3582 __ cvttsd2si(output_reg, xmm_scratch);
3583 // Overflow is signalled with minint.
3584 __ cmpl(output_reg, Immediate(0x80000000));
3585 __ RecordComment("D2I conversion overflow");
3586 DeoptimizeIf(equal, instr->environment());
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003587 __ jmp(&done, dist);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003588
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003589 __ bind(&below_one_half);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003590 __ movq(kScratchRegister, minus_one_half);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003591 __ movq(xmm_scratch, kScratchRegister);
3592 __ ucomisd(xmm_scratch, input_reg);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003593 __ j(below_equal, &round_to_zero, Label::kNear);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003594
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003595 // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
3596 // compare and compensate.
3597 __ movq(kScratchRegister, input_reg); // Back up input_reg.
3598 __ subsd(input_reg, xmm_scratch);
3599 __ cvttsd2si(output_reg, input_reg);
3600 // Catch minint due to overflow, and to prevent overflow when compensating.
3601 __ cmpl(output_reg, Immediate(0x80000000));
3602 __ RecordComment("D2I conversion overflow");
3603 DeoptimizeIf(equal, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003604
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003605 __ Cvtlsi2sd(xmm_scratch, output_reg);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003606 __ ucomisd(input_reg, xmm_scratch);
3607 __ j(equal, &restore, Label::kNear);
3608 __ subl(output_reg, Immediate(1));
3609 // No overflow because we already ruled out minint.
3610 __ bind(&restore);
3611 __ movq(input_reg, kScratchRegister); // Restore input_reg.
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003612 __ jmp(&done, dist);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003613
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003614 __ bind(&round_to_zero);
3615 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
3616 // we can ignore the difference between a result of -0 and +0.
3617 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3618 __ movq(output_reg, input_reg);
3619 __ testq(output_reg, output_reg);
3620 __ RecordComment("Minus zero");
3621 DeoptimizeIf(negative, instr->environment());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003622 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003623 __ Set(output_reg, 0);
3624 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003625}
3626
3627
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003628void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003629 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003630 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
3631 __ sqrtsd(input_reg, input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003632}
3633
3634
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003635void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003636 XMMRegister xmm_scratch = double_scratch0();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003637 XMMRegister input_reg = ToDoubleRegister(instr->value());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003638 ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003639
3640 // Note that according to ECMA-262 15.8.2.13:
3641 // Math.pow(-Infinity, 0.5) == Infinity
3642 // Math.sqrt(-Infinity) == NaN
3643 Label done, sqrt;
3644 // Check base for -Infinity. According to IEEE-754, double-precision
3645 // -Infinity has the highest 12 bits set and the lowest 52 bits cleared.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00003646 __ movq(kScratchRegister, V8_INT64_C(0xFFF0000000000000));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003647 __ movq(xmm_scratch, kScratchRegister);
3648 __ ucomisd(xmm_scratch, input_reg);
3649 // Comparing -Infinity with NaN results in "unordered", which sets the
3650 // zero flag as if both were equal. However, it also sets the carry flag.
3651 __ j(not_equal, &sqrt, Label::kNear);
3652 __ j(carry, &sqrt, Label::kNear);
3653 // If input is -Infinity, return Infinity.
3654 __ xorps(input_reg, input_reg);
3655 __ subsd(input_reg, xmm_scratch);
3656 __ jmp(&done, Label::kNear);
3657
3658 // Square root.
3659 __ bind(&sqrt);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003660 __ xorps(xmm_scratch, xmm_scratch);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003661 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
3662 __ sqrtsd(input_reg, input_reg);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003663 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003664}
3665
3666
3667void LCodeGen::DoPower(LPower* instr) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003668 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003669 // Having marked this as a call, we can use any registers.
3670 // Just make sure that the input/output registers are the expected ones.
3671
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003672 Register exponent = rdx;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003673 ASSERT(!instr->right()->IsRegister() ||
3674 ToRegister(instr->right()).is(exponent));
3675 ASSERT(!instr->right()->IsDoubleRegister() ||
3676 ToDoubleRegister(instr->right()).is(xmm1));
3677 ASSERT(ToDoubleRegister(instr->left()).is(xmm2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003678 ASSERT(ToDoubleRegister(instr->result()).is(xmm3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003679
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003680 if (exponent_type.IsSmi()) {
3681 MathPowStub stub(MathPowStub::TAGGED);
3682 __ CallStub(&stub);
3683 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003684 Label no_deopt;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003685 __ JumpIfSmi(exponent, &no_deopt, Label::kNear);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003686 __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, rcx);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003687 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003688 __ bind(&no_deopt);
3689 MathPowStub stub(MathPowStub::TAGGED);
3690 __ CallStub(&stub);
3691 } else if (exponent_type.IsInteger32()) {
3692 MathPowStub stub(MathPowStub::INTEGER);
3693 __ CallStub(&stub);
3694 } else {
3695 ASSERT(exponent_type.IsDouble());
3696 MathPowStub stub(MathPowStub::DOUBLE);
3697 __ CallStub(&stub);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003698 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003699}
3700
3701
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003702void LCodeGen::DoMathExp(LMathExp* instr) {
3703 XMMRegister input = ToDoubleRegister(instr->value());
3704 XMMRegister result = ToDoubleRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003705 XMMRegister temp0 = double_scratch0();
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003706 Register temp1 = ToRegister(instr->temp1());
3707 Register temp2 = ToRegister(instr->temp2());
3708
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003709 MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00003710}
3711
3712
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003713void LCodeGen::DoMathLog(LMathLog* instr) {
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003714 ASSERT(instr->value()->Equals(instr->result()));
3715 XMMRegister input_reg = ToDoubleRegister(instr->value());
3716 XMMRegister xmm_scratch = double_scratch0();
3717 Label positive, done, zero;
3718 __ xorps(xmm_scratch, xmm_scratch);
3719 __ ucomisd(input_reg, xmm_scratch);
3720 __ j(above, &positive, Label::kNear);
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003721 __ j(not_carry, &zero, Label::kNear);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00003722 ExternalReference nan =
3723 ExternalReference::address_of_canonical_non_hole_nan();
3724 Operand nan_operand = masm()->ExternalOperand(nan);
3725 __ movsd(input_reg, nan_operand);
3726 __ jmp(&done, Label::kNear);
3727 __ bind(&zero);
3728 ExternalReference ninf =
3729 ExternalReference::address_of_negative_infinity();
3730 Operand ninf_operand = masm()->ExternalOperand(ninf);
3731 __ movsd(input_reg, ninf_operand);
3732 __ jmp(&done, Label::kNear);
3733 __ bind(&positive);
3734 __ fldln2();
3735 __ subq(rsp, Immediate(kDoubleSize));
3736 __ movsd(Operand(rsp, 0), input_reg);
3737 __ fld_d(Operand(rsp, 0));
3738 __ fyl2x();
3739 __ fstp_d(Operand(rsp, 0));
3740 __ movsd(input_reg, Operand(rsp, 0));
3741 __ addq(rsp, Immediate(kDoubleSize));
3742 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003743}
3744
3745
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003746void LCodeGen::DoMathClz32(LMathClz32* instr) {
3747 Register input = ToRegister(instr->value());
3748 Register result = ToRegister(instr->result());
3749 Label not_zero_input;
3750 __ bsrl(result, input);
3751
3752 __ j(not_zero, &not_zero_input);
3753 __ Set(result, 63); // 63^31 == 32
3754
3755 __ bind(&not_zero_input);
3756 __ xorl(result, Immediate(31)); // for x in [0..31], 31^x == 31-x.
3757}
3758
3759
danno@chromium.org160a7b02011-04-18 15:51:38 +00003760void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003761 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.org160a7b02011-04-18 15:51:38 +00003762 ASSERT(ToRegister(instr->function()).is(rdi));
3763 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003764
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003765 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3766 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003767 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003768 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3769 ParameterCount count(instr->arity());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003770 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003771 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003772 CallKnownFunction(known_function,
3773 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003774 instr->arity(),
3775 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003776 RDI_CONTAINS_TARGET);
3777 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003778}
3779
3780
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003781void LCodeGen::DoCallFunction(LCallFunction* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003782 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003783 ASSERT(ToRegister(instr->function()).is(rdi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003784 ASSERT(ToRegister(instr->result()).is(rax));
3785
3786 int arity = instr->arity();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003787 CallFunctionStub stub(arity, instr->hydrogen()->function_flags());
3788 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003789}
3790
3791
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003792void LCodeGen::DoCallNew(LCallNew* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003793 ASSERT(ToRegister(instr->context()).is(rsi));
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
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003799 Handle<Object> megamorphic_symbol =
3800 TypeFeedbackInfo::MegamorphicSentinel(isolate());
3801 __ Move(rbx, megamorphic_symbol);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003802 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003803 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003804}
3805
3806
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003807void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003808 ASSERT(ToRegister(instr->context()).is(rsi));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003809 ASSERT(ToRegister(instr->constructor()).is(rdi));
3810 ASSERT(ToRegister(instr->result()).is(rax));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003811
3812 __ Set(rax, instr->arity());
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00003813 __ Move(rbx, TypeFeedbackInfo::MegamorphicSentinel(isolate()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003814 ElementsKind kind = instr->hydrogen()->elements_kind();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003815 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00003816 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003817 ? DISABLE_ALLOCATION_SITES
3818 : DONT_OVERRIDE;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003819
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003820 if (instr->arity() == 0) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003821 ArrayNoArgumentConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003822 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3823 } else if (instr->arity() == 1) {
danno@chromium.org41728482013-06-12 22:31:22 +00003824 Label done;
3825 if (IsFastPackedElementsKind(kind)) {
3826 Label packed_case;
3827 // We might need a change here
3828 // look at the first argument
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003829 __ movp(rcx, Operand(rsp, 0));
danno@chromium.org41728482013-06-12 22:31:22 +00003830 __ testq(rcx, rcx);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003831 __ j(zero, &packed_case, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00003832
3833 ElementsKind holey_kind = GetHoleyElementsKind(kind);
machenbach@chromium.org03453962014-01-10 14:16:31 +00003834 ArraySingleArgumentConstructorStub stub(holey_kind, override_mode);
danno@chromium.org41728482013-06-12 22:31:22 +00003835 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003836 __ jmp(&done, Label::kNear);
danno@chromium.org41728482013-06-12 22:31:22 +00003837 __ bind(&packed_case);
3838 }
3839
machenbach@chromium.org03453962014-01-10 14:16:31 +00003840 ArraySingleArgumentConstructorStub stub(kind, 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 {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003844 ArrayNArgumentsConstructorStub stub(kind, 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) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003851 ASSERT(ToRegister(instr->context()).is(rsi));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003852 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003853}
3854
3855
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003856void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
3857 Register function = ToRegister(instr->function());
3858 Register code_object = ToRegister(instr->code_object());
3859 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize));
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003860 __ movp(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003861}
3862
3863
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003864void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3865 Register result = ToRegister(instr->result());
3866 Register base = ToRegister(instr->base_object());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003867 if (instr->offset()->IsConstantOperand()) {
3868 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
3869 __ lea(result, Operand(base, ToInteger32(offset)));
3870 } else {
3871 Register offset = ToRegister(instr->offset());
3872 __ lea(result, Operand(base, offset, times_1, 0));
3873 }
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00003874}
3875
3876
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003877void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003878 HStoreNamedField* hinstr = instr->hydrogen();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003879 Representation representation = instr->representation();
3880
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003881 HObjectAccess access = hinstr->access();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003882 int offset = access.offset();
ager@chromium.org378b34e2011-01-28 08:04:38 +00003883
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003884 if (access.IsExternalMemory()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003885 ASSERT(!hinstr->NeedsWriteBarrier());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003886 Register value = ToRegister(instr->value());
3887 if (instr->object()->IsConstantOperand()) {
3888 ASSERT(value.is(rax));
3889 LConstantOperand* object = LConstantOperand::cast(instr->object());
3890 __ store_rax(ToExternalReference(object));
3891 } else {
3892 Register object = ToRegister(instr->object());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003893 __ Store(MemOperand(object, offset), value, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003894 }
3895 return;
3896 }
3897
3898 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003899 Handle<Map> transition = instr->transition();
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003900 SmiCheck check_needed = hinstr->value()->IsHeapObject()
3901 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003902
titzer@chromium.orgbc176052014-03-05 15:10:53 +00003903 if (representation.IsSmi()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003904 if (instr->value()->IsConstantOperand()) {
3905 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003906 if (!IsInteger32Constant(operand_value) &&
3907 !IsSmiConstant(operand_value)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003908 DeoptimizeIf(no_condition, instr->environment());
3909 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003910 }
titzer@chromium.orgbc176052014-03-05 15:10:53 +00003911 } else if (representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003912 if (instr->value()->IsConstantOperand()) {
3913 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
3914 if (IsInteger32Constant(operand_value)) {
3915 DeoptimizeIf(no_condition, instr->environment());
3916 }
3917 } else {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003918 if (!hinstr->value()->type().IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003919 Register value = ToRegister(instr->value());
3920 Condition cc = masm()->CheckSmi(value);
3921 DeoptimizeIf(cc, instr->environment());
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003922
3923 // We know that value is a smi now, so we can omit the check below.
3924 check_needed = OMIT_SMI_CHECK;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003925 }
3926 }
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00003927 } else if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003928 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003929 ASSERT(access.IsInobject());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003930 ASSERT(!hinstr->NeedsWriteBarrier());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003931 XMMRegister value = ToDoubleRegister(instr->value());
3932 __ movsd(FieldOperand(object, offset), value);
3933 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003934 }
3935
danno@chromium.orgf005df62013-04-30 16:36:45 +00003936 if (!transition.is_null()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003937 if (!hinstr->NeedsWriteBarrierForMap()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003938 __ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003939 } else {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00003940 Register temp = ToRegister(instr->temp());
danno@chromium.orgf005df62013-04-30 16:36:45 +00003941 __ Move(kScratchRegister, transition);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003942 __ movp(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003943 // Update the write barrier for the map field.
3944 __ RecordWriteField(object,
3945 HeapObject::kMapOffset,
3946 kScratchRegister,
3947 temp,
3948 kSaveFPRegs,
3949 OMIT_REMEMBERED_SET,
3950 OMIT_SMI_CHECK);
3951 }
ager@chromium.org378b34e2011-01-28 08:04:38 +00003952 }
3953
3954 // Do the store.
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003955 Register write_register = object;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003956 if (!access.IsInobject()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003957 write_register = ToRegister(instr->temp());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00003958 __ movp(write_register, FieldOperand(object, JSObject::kPropertiesOffset));
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003959 }
3960
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003961 if (representation.IsSmi() &&
3962 hinstr->value()->representation().IsInteger32()) {
3963 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00003964#ifdef DEBUG
3965 Register scratch = kScratchRegister;
3966 __ Load(scratch, FieldOperand(write_register, offset), representation);
3967 __ AssertSmi(scratch);
3968#endif
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003969 // Store int value directly to upper half of the smi.
3970 STATIC_ASSERT(kSmiTag == 0);
3971 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
3972 offset += kPointerSize / 2;
3973 representation = Representation::Integer32();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00003974 }
3975
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00003976 Operand operand = FieldOperand(write_register, offset);
3977
3978 if (instr->value()->IsRegister()) {
3979 Register value = ToRegister(instr->value());
3980 __ Store(operand, value, representation);
3981 } else {
3982 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
3983 if (IsInteger32Constant(operand_value)) {
3984 ASSERT(!hinstr->NeedsWriteBarrier());
3985 int32_t value = ToInteger32(operand_value);
3986 if (representation.IsSmi()) {
3987 __ Move(operand, Smi::FromInt(value));
3988
3989 } else {
3990 __ movl(operand, Immediate(value));
3991 }
3992
3993 } else {
3994 Handle<Object> handle_value = ToHandle(operand_value);
3995 ASSERT(!hinstr->NeedsWriteBarrier());
3996 __ Move(operand, handle_value);
3997 }
3998 }
3999
4000 if (hinstr->NeedsWriteBarrier()) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004001 Register value = ToRegister(instr->value());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004002 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004003 // Update the write barrier for the object for in-object properties.
4004 __ RecordWriteField(write_register,
4005 offset,
4006 value,
4007 temp,
4008 kSaveFPRegs,
4009 EMIT_REMEMBERED_SET,
4010 check_needed);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004011 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004012}
4013
4014
4015void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004016 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004017 ASSERT(ToRegister(instr->object()).is(rdx));
4018 ASSERT(ToRegister(instr->value()).is(rax));
4019
4020 __ Move(rcx, instr->hydrogen()->name());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004021 Handle<Code> ic = StoreIC::initialize_stub(isolate(),
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004022 instr->strict_mode_flag());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004023 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4024}
4025
4026
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004027void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) {
4028 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4029 Label done;
4030 __ j(NegateCondition(cc), &done, Label::kNear);
4031 __ int3();
4032 __ bind(&done);
4033 } else {
4034 DeoptimizeIf(cc, check->environment());
4035 }
4036}
4037
4038
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004039void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004040 HBoundsCheck* hinstr = instr->hydrogen();
4041 if (hinstr->skip_check()) return;
4042
4043 Representation representation = hinstr->length()->representation();
4044 ASSERT(representation.Equals(hinstr->index()->representation()));
4045 ASSERT(representation.IsSmiOrInteger32());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004047 if (instr->length()->IsRegister()) {
4048 Register reg = ToRegister(instr->length());
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004049
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004050 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004051 int32_t constant_index =
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004052 ToInteger32(LConstantOperand::cast(instr->index()));
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004053 if (representation.IsSmi()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004054 __ Cmp(reg, Smi::FromInt(constant_index));
4055 } else {
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004056 __ cmpl(reg, Immediate(constant_index));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004057 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004058 } else {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004059 Register reg2 = ToRegister(instr->index());
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004060 if (representation.IsSmi()) {
4061 __ cmpq(reg, reg2);
4062 } else {
4063 __ cmpl(reg, reg2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004064 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004065 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004066 } else {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004067 Operand length = ToOperand(instr->length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004068 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004069 int32_t constant_index =
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004070 ToInteger32(LConstantOperand::cast(instr->index()));
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004071 if (representation.IsSmi()) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004072 __ Cmp(length, Smi::FromInt(constant_index));
4073 } else {
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004074 __ cmpl(length, Immediate(constant_index));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004075 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004076 } else {
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004077 if (representation.IsSmi()) {
4078 __ cmpq(length, ToRegister(instr->index()));
4079 } else {
4080 __ cmpl(length, ToRegister(instr->index()));
4081 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004082 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004083 }
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00004084 Condition condition = hinstr->allow_equality() ? below : below_equal;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004085 ApplyCheckIf(condition, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004086}
4087
4088
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004089void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4090 ElementsKind elements_kind = instr->elements_kind();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004091 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004092 if (!key->IsConstantOperand()) {
4093 Register key_reg = ToRegister(key);
4094 // Even though the HLoad/StoreKeyedFastElement instructions force
4095 // the input representation for the key to be an integer, the input
4096 // gets replaced during bound check elimination with the index
4097 // argument to the bounds check, which can be tagged, so that case
4098 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004099 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004100 // Sign extend key because it could be a 32 bit negative value
4101 // and the dehoisted address computation happens in 64 bits
4102 __ movsxlq(key_reg, key_reg);
4103 }
4104 }
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004105 int base_offset = instr->is_fixed_typed_array()
4106 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag
4107 : 0;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004108 Operand operand(BuildFastArrayOperand(
4109 instr->elements(),
4110 key,
4111 elements_kind,
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004112 base_offset,
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004113 instr->additional_index()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004114
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004115 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004116 elements_kind == FLOAT32_ELEMENTS) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004117 XMMRegister value(ToDoubleRegister(instr->value()));
4118 __ cvtsd2ss(value, value);
4119 __ movss(operand, value);
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004120 } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004121 elements_kind == FLOAT64_ELEMENTS) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004122 __ movsd(operand, ToDoubleRegister(instr->value()));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004123 } else {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004124 Register value(ToRegister(instr->value()));
4125 switch (elements_kind) {
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004126 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
4127 case EXTERNAL_INT8_ELEMENTS:
4128 case EXTERNAL_UINT8_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004129 case INT8_ELEMENTS:
4130 case UINT8_ELEMENTS:
4131 case UINT8_CLAMPED_ELEMENTS:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004132 __ movb(operand, value);
4133 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004134 case EXTERNAL_INT16_ELEMENTS:
4135 case EXTERNAL_UINT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004136 case INT16_ELEMENTS:
4137 case UINT16_ELEMENTS:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004138 __ movw(operand, value);
4139 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004140 case EXTERNAL_INT32_ELEMENTS:
4141 case EXTERNAL_UINT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004142 case INT32_ELEMENTS:
4143 case UINT32_ELEMENTS:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004144 __ movl(operand, value);
4145 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004146 case EXTERNAL_FLOAT32_ELEMENTS:
4147 case EXTERNAL_FLOAT64_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004148 case FLOAT32_ELEMENTS:
4149 case FLOAT64_ELEMENTS:
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004150 case FAST_ELEMENTS:
4151 case FAST_SMI_ELEMENTS:
4152 case FAST_DOUBLE_ELEMENTS:
4153 case FAST_HOLEY_ELEMENTS:
4154 case FAST_HOLEY_SMI_ELEMENTS:
4155 case FAST_HOLEY_DOUBLE_ELEMENTS:
4156 case DICTIONARY_ELEMENTS:
4157 case NON_STRICT_ARGUMENTS_ELEMENTS:
4158 UNREACHABLE();
4159 break;
4160 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004161 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004162}
4163
4164
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004165void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004166 XMMRegister value = ToDoubleRegister(instr->value());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004167 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004168 if (!key->IsConstantOperand()) {
4169 Register key_reg = ToRegister(key);
4170 // Even though the HLoad/StoreKeyedFastElement instructions force
4171 // the input representation for the key to be an integer, the
4172 // input gets replaced during bound check elimination with the index
4173 // argument to the bounds check, which can be tagged, so that case
4174 // must be handled here, too.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004175 if (instr->hydrogen()->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004176 // Sign extend key because it could be a 32 bit negative value
4177 // and the dehoisted address computation happens in 64 bits
4178 __ movsxlq(key_reg, key_reg);
4179 }
4180 }
4181
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004182 if (instr->NeedsCanonicalization()) {
4183 Label have_value;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004184
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004185 __ ucomisd(value, value);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004186 __ j(parity_odd, &have_value, Label::kNear); // NaN.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004187
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00004188 __ Set(kScratchRegister, BitCast<uint64_t>(
4189 FixedDoubleArray::canonical_not_the_hole_nan_as_double()));
4190 __ movq(value, kScratchRegister);
4191
4192 __ bind(&have_value);
4193 }
4194
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004195 Operand double_store_operand = BuildFastArrayOperand(
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004196 instr->elements(),
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004197 key,
ulan@chromium.org0e3f88b2012-05-22 09:16:05 +00004198 FAST_DOUBLE_ELEMENTS,
4199 FixedDoubleArray::kHeaderSize - kHeapObjectTag,
4200 instr->additional_index());
4201
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004202 __ movsd(double_store_operand, value);
4203}
4204
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004205
4206void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004207 HStoreKeyed* hinstr = instr->hydrogen();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004208 LOperand* key = instr->key();
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004209 if (!key->IsConstantOperand()) {
4210 Register key_reg = ToRegister(key);
4211 // Even though the HLoad/StoreKeyedFastElement instructions force
4212 // the input representation for the key to be an integer, the
4213 // input gets replaced during bound check elimination with the index
4214 // argument to the bounds check, which can be tagged, so that case
4215 // must be handled here, too.
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004216 if (hinstr->IsDehoisted()) {
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00004217 // Sign extend key because it could be a 32 bit negative value
4218 // and the dehoisted address computation happens in 64 bits
4219 __ movsxlq(key_reg, key_reg);
4220 }
4221 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004222
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004223 int offset = FixedArray::kHeaderSize - kHeapObjectTag;
4224 Representation representation = hinstr->value()->representation();
4225
4226 if (representation.IsInteger32()) {
4227 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY);
4228 ASSERT(hinstr->elements_kind() == FAST_SMI_ELEMENTS);
titzer@chromium.orgf5a24542014-03-04 09:06:17 +00004229#ifdef DEBUG
4230 Register scratch = kScratchRegister;
4231 __ Load(scratch,
4232 BuildFastArrayOperand(instr->elements(),
4233 key,
4234 FAST_ELEMENTS,
4235 offset,
4236 instr->additional_index()),
4237 Representation::Smi());
4238 __ AssertSmi(scratch);
4239#endif
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004240 // Store int value directly to upper half of the smi.
4241 STATIC_ASSERT(kSmiTag == 0);
4242 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32);
4243 offset += kPointerSize / 2;
4244 }
4245
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004246 Operand operand =
4247 BuildFastArrayOperand(instr->elements(),
4248 key,
4249 FAST_ELEMENTS,
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004250 offset,
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004251 instr->additional_index());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004252
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004253 if (instr->value()->IsRegister()) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004254 __ Store(operand, ToRegister(instr->value()), representation);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004255 } else {
4256 LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
4257 if (IsInteger32Constant(operand_value)) {
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004258 int32_t value = ToInteger32(operand_value);
4259 if (representation.IsSmi()) {
4260 __ Move(operand, Smi::FromInt(value));
4261
4262 } else {
4263 __ movl(operand, Immediate(value));
4264 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004265 } else {
4266 Handle<Object> handle_value = ToHandle(operand_value);
4267 __ Move(operand, handle_value);
4268 }
4269 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004270
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004271 if (hinstr->NeedsWriteBarrier()) {
4272 Register elements = ToRegister(instr->elements());
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004273 ASSERT(instr->value()->IsRegister());
4274 Register value = ToRegister(instr->value());
hpayer@chromium.org71ea97f2013-12-19 16:03:26 +00004275 ASSERT(!key->IsConstantOperand());
4276 SmiCheck check_needed = hinstr->value()->IsHeapObject()
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004277 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004278 // Compute address of modified element and store it into key register.
4279 Register key_reg(ToRegister(key));
4280 __ lea(key_reg, operand);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004281 __ RecordWrite(elements,
4282 key_reg,
4283 value,
4284 kSaveFPRegs,
4285 EMIT_REMEMBERED_SET,
4286 check_needed);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004287 }
4288}
4289
4290
4291void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004292 if (instr->is_typed_elements()) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00004293 DoStoreKeyedExternalArray(instr);
4294 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4295 DoStoreKeyedFixedDoubleArray(instr);
4296 } else {
4297 DoStoreKeyedFixedArray(instr);
4298 }
4299}
4300
4301
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004302void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004303 ASSERT(ToRegister(instr->context()).is(rsi));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004304 ASSERT(ToRegister(instr->object()).is(rdx));
4305 ASSERT(ToRegister(instr->key()).is(rcx));
4306 ASSERT(ToRegister(instr->value()).is(rax));
4307
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004308 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004309 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4310 : isolate()->builtins()->KeyedStoreIC_Initialize();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004311 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4312}
4313
4314
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004315void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4316 Register object_reg = ToRegister(instr->object());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004317
4318 Handle<Map> from_map = instr->original_map();
4319 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004320 ElementsKind from_kind = instr->from_kind();
4321 ElementsKind to_kind = instr->to_kind();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004322
4323 Label not_applicable;
4324 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
4325 __ j(not_equal, &not_applicable);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004326 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004327 Register new_map_reg = ToRegister(instr->new_map_temp());
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004328 __ Move(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004329 __ movp(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004330 // Write barrier.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004331 ASSERT_NE(instr->temp(), NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004332 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004333 ToRegister(instr->temp()), kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004334 } else {
yangguo@chromium.orgcc536052013-11-29 11:43:20 +00004335 ASSERT(ToRegister(instr->context()).is(rsi));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004336 PushSafepointRegistersScope scope(this);
4337 if (!object_reg.is(rax)) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004338 __ movp(rax, object_reg);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004339 }
4340 __ Move(rbx, to_map);
4341 TransitionElementsKindStub stub(from_kind, to_kind);
4342 __ CallStub(&stub);
4343 RecordSafepointWithRegisters(
4344 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004345 }
4346 __ bind(&not_applicable);
4347}
4348
4349
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004350void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4351 Register object = ToRegister(instr->object());
4352 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004353 Label no_memento_found;
4354 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004355 DeoptimizeIf(equal, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004356 __ bind(&no_memento_found);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004357}
4358
4359
danno@chromium.org160a7b02011-04-18 15:51:38 +00004360void LCodeGen::DoStringAdd(LStringAdd* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004361 ASSERT(ToRegister(instr->context()).is(rsi));
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00004362 ASSERT(ToRegister(instr->left()).is(rdx));
4363 ASSERT(ToRegister(instr->right()).is(rax));
4364 StringAddStub stub(instr->hydrogen()->flags(),
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00004365 instr->hydrogen()->pretenure_flag());
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00004366 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
danno@chromium.org160a7b02011-04-18 15:51:38 +00004367}
4368
4369
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004370void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004371 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004372 public:
4373 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4374 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004375 virtual void Generate() V8_OVERRIDE {
4376 codegen()->DoDeferredStringCharCodeAt(instr_);
4377 }
4378 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004379 private:
4380 LStringCharCodeAt* instr_;
4381 };
4382
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004383 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004384 new(zone()) DeferredStringCharCodeAt(this, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004385
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004386 StringCharLoadGenerator::Generate(masm(),
4387 ToRegister(instr->string()),
4388 ToRegister(instr->index()),
4389 ToRegister(instr->result()),
4390 deferred->entry());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004391 __ bind(deferred->exit());
4392}
4393
4394
4395void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4396 Register string = ToRegister(instr->string());
4397 Register result = ToRegister(instr->result());
4398
4399 // TODO(3095996): Get rid of this. For now, we need to make the
4400 // result register contain a valid pointer because it is already
4401 // contained in the register pointer map.
4402 __ Set(result, 0);
4403
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004404 PushSafepointRegistersScope scope(this);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004405 __ push(string);
4406 // Push the index as a smi. This is safe because of the checks in
4407 // DoStringCharCodeAt above.
4408 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
4409 if (instr->index()->IsConstantOperand()) {
danno@chromium.org59400602013-08-13 17:09:37 +00004410 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index()));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004411 __ Push(Smi::FromInt(const_index));
4412 } else {
4413 Register index = ToRegister(instr->index());
4414 __ Integer32ToSmi(index, index);
4415 __ push(index);
4416 }
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004417 CallRuntimeFromDeferred(
4418 Runtime::kStringCharCodeAt, 2, instr, instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004419 __ AssertSmi(rax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004420 __ SmiToInteger32(rax, rax);
4421 __ StoreToSafepointRegisterSlot(result, rax);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004422}
4423
4424
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004425void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004426 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004427 public:
4428 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4429 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004430 virtual void Generate() V8_OVERRIDE {
4431 codegen()->DoDeferredStringCharFromCode(instr_);
4432 }
4433 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004434 private:
4435 LStringCharFromCode* instr_;
4436 };
4437
4438 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004439 new(zone()) DeferredStringCharFromCode(this, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004440
4441 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4442 Register char_code = ToRegister(instr->char_code());
4443 Register result = ToRegister(instr->result());
4444 ASSERT(!char_code.is(result));
4445
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004446 __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004447 __ j(above, deferred->entry());
danno@chromium.orgf005df62013-04-30 16:36:45 +00004448 __ movsxlq(char_code, char_code);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004449 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004450 __ movp(result, FieldOperand(result,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004451 char_code, times_pointer_size,
4452 FixedArray::kHeaderSize));
4453 __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
4454 __ j(equal, deferred->entry());
4455 __ bind(deferred->exit());
4456}
4457
4458
4459void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4460 Register char_code = ToRegister(instr->char_code());
4461 Register result = ToRegister(instr->result());
4462
4463 // TODO(3095996): Get rid of this. For now, we need to make the
4464 // result register contain a valid pointer because it is already
4465 // contained in the register pointer map.
4466 __ Set(result, 0);
4467
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004468 PushSafepointRegistersScope scope(this);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004469 __ Integer32ToSmi(char_code, char_code);
4470 __ push(char_code);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004471 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004472 __ StoreToSafepointRegisterSlot(result, rax);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00004473}
4474
4475
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004476void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004477 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004478 ASSERT(input->IsRegister() || input->IsStackSlot());
4479 LOperand* output = instr->result();
4480 ASSERT(output->IsDoubleRegister());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004481 if (input->IsRegister()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004482 __ Cvtlsi2sd(ToDoubleRegister(output), ToRegister(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004483 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004484 __ Cvtlsi2sd(ToDoubleRegister(output), ToOperand(input));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004485 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004486}
4487
4488
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004489void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4490 LOperand* input = instr->value();
4491 ASSERT(input->IsRegister());
4492 LOperand* output = instr->result();
4493 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4494 if (!instr->hydrogen()->value()->HasRange() ||
4495 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4496 DeoptimizeIf(overflow, instr->environment());
4497 }
4498}
4499
4500
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004501void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004502 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004503 LOperand* output = instr->result();
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004504 LOperand* temp = instr->temp();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004505
4506 __ LoadUint32(ToDoubleRegister(output),
4507 ToRegister(input),
4508 ToDoubleRegister(temp));
4509}
4510
4511
machenbach@chromium.orged29eb22013-10-31 13:30:00 +00004512void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4513 LOperand* input = instr->value();
4514 ASSERT(input->IsRegister());
4515 LOperand* output = instr->result();
4516 if (!instr->hydrogen()->value()->HasRange() ||
4517 !instr->hydrogen()->value()->range()->IsInSmiRange() ||
4518 instr->hydrogen()->value()->range()->upper() == kMaxInt) {
4519 // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
4520 // interval, so we treat kMaxInt as a sentinel for this entire interval.
4521 __ testl(ToRegister(input), Immediate(0x80000000));
4522 DeoptimizeIf(not_zero, instr->environment());
4523 }
4524 __ Integer32ToSmi(ToRegister(output), ToRegister(input));
4525}
4526
4527
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004528void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004529 LOperand* input = instr->value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004530 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4531 Register reg = ToRegister(input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004532
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004533 __ Integer32ToSmi(reg, reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004534}
4535
4536
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004537void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004538 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004539 public:
4540 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4541 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004542 virtual void Generate() V8_OVERRIDE {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004543 codegen()->DoDeferredNumberTagU(instr_);
4544 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004545 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004546 private:
4547 LNumberTagU* instr_;
4548 };
4549
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004550 LOperand* input = instr->value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004551 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4552 Register reg = ToRegister(input);
4553
4554 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4555 __ cmpl(reg, Immediate(Smi::kMaxValue));
4556 __ j(above, deferred->entry());
4557 __ Integer32ToSmi(reg, reg);
4558 __ bind(deferred->exit());
4559}
4560
4561
4562void LCodeGen::DoDeferredNumberTagU(LNumberTagU* instr) {
titzer@chromium.orgbc176052014-03-05 15:10:53 +00004563 Label done, slow;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004564 Register reg = ToRegister(instr->value());
titzer@chromium.orgbc176052014-03-05 15:10:53 +00004565 Register tmp = ToRegister(instr->temp1());
4566 XMMRegister temp_xmm = ToDoubleRegister(instr->temp2());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004567
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004568 // Load value into temp_xmm which will be preserved across potential call to
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004569 // runtime (MacroAssembler::EnterExitFrameEpilogue preserves only allocatable
4570 // XMM registers on x64).
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004571 XMMRegister xmm_scratch = double_scratch0();
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004572 __ LoadUint32(temp_xmm, reg, xmm_scratch);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004573
4574 if (FLAG_inline_new) {
4575 __ AllocateHeapNumber(reg, tmp, &slow);
4576 __ jmp(&done, Label::kNear);
4577 }
4578
4579 // Slow case: Call the runtime system to do the number allocation.
4580 __ bind(&slow);
titzer@chromium.orgbc176052014-03-05 15:10:53 +00004581 {
4582 // Put a valid pointer value in the stack slot where the result
4583 // register is stored, as this register is in the pointer map, but contains
4584 // an integer value.
4585 __ Set(reg, 0);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004586
titzer@chromium.orgbc176052014-03-05 15:10:53 +00004587 // Preserve the value of all registers.
4588 PushSafepointRegistersScope scope(this);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004589
titzer@chromium.orgbc176052014-03-05 15:10:53 +00004590 // NumberTagU uses the context from the frame, rather than
4591 // the environment's HContext or HInlinedContext value.
4592 // They only call Runtime::kAllocateHeapNumber.
4593 // The corresponding HChange instructions are added in a phase that does
4594 // not have easy access to the local context.
4595 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
4596 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4597 RecordSafepointWithRegisters(
4598 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
4599 __ StoreToSafepointRegisterSlot(reg, rax);
4600 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004601
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004602 // Done. Put the value in temp_xmm into the value of the allocated heap
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004603 // number.
4604 __ bind(&done);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00004605 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004606}
4607
4608
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004609void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004610 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004611 public:
4612 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4613 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004614 virtual void Generate() V8_OVERRIDE {
4615 codegen()->DoDeferredNumberTagD(instr_);
4616 }
4617 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004618 private:
4619 LNumberTagD* instr_;
4620 };
4621
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004622 XMMRegister input_reg = ToDoubleRegister(instr->value());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004623 Register reg = ToRegister(instr->result());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004624 Register tmp = ToRegister(instr->temp());
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004625
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004626 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004627 if (FLAG_inline_new) {
4628 __ AllocateHeapNumber(reg, tmp, deferred->entry());
4629 } else {
4630 __ jmp(deferred->entry());
4631 }
4632 __ bind(deferred->exit());
4633 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004634}
4635
4636
4637void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004638 // TODO(3095996): Get rid of this. For now, we need to make the
4639 // result register contain a valid pointer because it is already
4640 // contained in the register pointer map.
4641 Register reg = ToRegister(instr->result());
4642 __ Move(reg, Smi::FromInt(0));
4643
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004644 {
4645 PushSafepointRegistersScope scope(this);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004646 // NumberTagD uses the context from the frame, rather than
4647 // the environment's HContext or HInlinedContext value.
4648 // They only call Runtime::kAllocateHeapNumber.
4649 // The corresponding HChange instructions are added in a phase that does
4650 // not have easy access to the local context.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004651 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004652 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4653 RecordSafepointWithRegisters(
4654 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004655 __ movp(kScratchRegister, rax);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004656 }
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004657 __ movp(reg, kScratchRegister);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004658}
4659
4660
4661void LCodeGen::DoSmiTag(LSmiTag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004662 ASSERT(instr->value()->Equals(instr->result()));
4663 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004664 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
4665 __ Integer32ToSmi(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004666}
4667
4668
4669void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004670 ASSERT(instr->value()->Equals(instr->result()));
4671 Register input = ToRegister(instr->value());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004672 if (instr->needs_check()) {
4673 Condition is_smi = __ CheckSmi(input);
4674 DeoptimizeIf(NegateCondition(is_smi), instr->environment());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004675 } else {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004676 __ AssertSmi(input);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004677 }
4678 __ SmiToInteger32(input, input);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004679}
4680
4681
4682void LCodeGen::EmitNumberUntagD(Register input_reg,
4683 XMMRegister result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004684 bool can_convert_undefined_to_nan,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004685 bool deoptimize_on_minus_zero,
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004686 LEnvironment* env,
4687 NumberUntagDMode mode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004688 Label convert, load_smi, done;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004689
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004690 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004691 // Smi check.
4692 __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004693
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004694 // Heap number map check.
4695 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4696 Heap::kHeapNumberMapRootIndex);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00004697
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004698 // On x64 it is safe to load at heap number offset before evaluating the map
4699 // check, since all heap objects are at least two words long.
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004700 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004701
4702 if (can_convert_undefined_to_nan) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004703 __ j(not_equal, &convert, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004704 } else {
4705 DeoptimizeIf(not_equal, env);
4706 }
4707
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004708 if (deoptimize_on_minus_zero) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004709 XMMRegister xmm_scratch = double_scratch0();
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004710 __ xorps(xmm_scratch, xmm_scratch);
4711 __ ucomisd(xmm_scratch, result_reg);
4712 __ j(not_equal, &done, Label::kNear);
4713 __ movmskpd(kScratchRegister, result_reg);
4714 __ testq(kScratchRegister, Immediate(1));
4715 DeoptimizeIf(not_zero, env);
4716 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004717 __ jmp(&done, Label::kNear);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004718
4719 if (can_convert_undefined_to_nan) {
4720 __ bind(&convert);
4721
4722 // Convert undefined (and hole) to NaN. Compute NaN as 0/0.
4723 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
4724 DeoptimizeIf(not_equal, env);
4725
4726 __ xorps(result_reg, result_reg);
4727 __ divsd(result_reg, result_reg);
4728 __ jmp(&done, Label::kNear);
4729 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004730 } else {
4731 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004732 }
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004733
4734 // Smi to XMM conversion
4735 __ bind(&load_smi);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004736 __ SmiToInteger32(kScratchRegister, input_reg);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004737 __ Cvtlsi2sd(result_reg, kScratchRegister);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00004738 __ bind(&done);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004739}
4740
4741
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004742void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004743 Register input_reg = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004744
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004745 if (instr->truncating()) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004746 Label no_heap_number, check_bools, check_false;
4747
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004748 // Heap number map check.
4749 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset),
4750 Heap::kHeapNumberMapRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004751 __ j(not_equal, &no_heap_number, Label::kNear);
4752 __ TruncateHeapNumberToI(input_reg, input_reg);
4753 __ jmp(done);
4754
4755 __ bind(&no_heap_number);
4756 // Check for Oddballs. Undefined/False is converted to zero and True to one
4757 // for truncating conversions.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004758 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004759 __ j(not_equal, &check_bools, Label::kNear);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004760 __ Set(input_reg, 0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004761 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004762
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004763 __ bind(&check_bools);
4764 __ CompareRoot(input_reg, Heap::kTrueValueRootIndex);
4765 __ j(not_equal, &check_false, Label::kNear);
4766 __ Set(input_reg, 1);
4767 __ jmp(done);
4768
4769 __ bind(&check_false);
4770 __ CompareRoot(input_reg, Heap::kFalseValueRootIndex);
4771 __ RecordComment("Deferred TaggedToI: cannot truncate");
4772 DeoptimizeIf(not_equal, instr->environment());
4773 __ Set(input_reg, 0);
4774 __ jmp(done);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004775 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004776 Label bailout;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004777 XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004778 __ TaggedToI(input_reg, input_reg, xmm_temp,
4779 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4780
4781 __ jmp(done);
4782 __ bind(&bailout);
4783 DeoptimizeIf(no_condition, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004784 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004785}
4786
4787
4788void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004789 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004790 public:
4791 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4792 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004793 virtual void Generate() V8_OVERRIDE {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004794 codegen()->DoDeferredTaggedToI(instr_, done());
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004795 }
4796 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004797 private:
4798 LTaggedToI* instr_;
4799 };
4800
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004801 LOperand* input = instr->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004802 ASSERT(input->IsRegister());
4803 ASSERT(input->Equals(instr->result()));
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004804 Register input_reg = ToRegister(input);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004805
4806 if (instr->hydrogen()->value()->representation().IsSmi()) {
4807 __ SmiToInteger32(input_reg, input_reg);
4808 } else {
4809 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
4810 __ JumpIfNotSmi(input_reg, deferred->entry());
4811 __ SmiToInteger32(input_reg, input_reg);
4812 __ bind(deferred->exit());
4813 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004814}
4815
4816
4817void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004818 LOperand* input = instr->value();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004819 ASSERT(input->IsRegister());
4820 LOperand* result = instr->result();
4821 ASSERT(result->IsDoubleRegister());
4822
4823 Register input_reg = ToRegister(input);
4824 XMMRegister result_reg = ToDoubleRegister(result);
4825
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004826 HValue* value = instr->hydrogen()->value();
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004827 NumberUntagDMode mode = value->representation().IsSmi()
4828 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004829
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004830 EmitNumberUntagD(input_reg, result_reg,
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004831 instr->hydrogen()->can_convert_undefined_to_nan(),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004832 instr->hydrogen()->deoptimize_on_minus_zero(),
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00004833 instr->environment(),
4834 mode);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004835}
4836
4837
4838void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004839 LOperand* input = instr->value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004840 ASSERT(input->IsDoubleRegister());
4841 LOperand* result = instr->result();
4842 ASSERT(result->IsRegister());
4843
4844 XMMRegister input_reg = ToDoubleRegister(input);
4845 Register result_reg = ToRegister(result);
4846
4847 if (instr->truncating()) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004848 __ TruncateDoubleToI(result_reg, input_reg);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004849 } else {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004850 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004851 XMMRegister xmm_scratch = double_scratch0();
4852 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004853 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
4854
4855 __ jmp(&done, Label::kNear);
4856 __ bind(&bailout);
4857 DeoptimizeIf(no_condition, instr->environment());
4858 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004859 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004860}
4861
4862
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004863void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4864 LOperand* input = instr->value();
4865 ASSERT(input->IsDoubleRegister());
4866 LOperand* result = instr->result();
4867 ASSERT(result->IsRegister());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004868
4869 XMMRegister input_reg = ToDoubleRegister(input);
4870 Register result_reg = ToRegister(result);
4871
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004872 Label bailout, done;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004873 XMMRegister xmm_scratch = double_scratch0();
4874 __ DoubleToI(result_reg, input_reg, xmm_scratch,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004875 instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004876
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004877 __ jmp(&done, Label::kNear);
4878 __ bind(&bailout);
4879 DeoptimizeIf(no_condition, instr->environment());
4880 __ bind(&done);
4881
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004882 __ Integer32ToSmi(result_reg, result_reg);
4883 DeoptimizeIf(overflow, instr->environment());
4884}
4885
4886
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004887void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004888 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004889 Condition cc = masm()->CheckSmi(ToRegister(input));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004890 DeoptimizeIf(NegateCondition(cc), instr->environment());
4891}
4892
4893
4894void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004895 if (!instr->hydrogen()->value()->IsHeapObject()) {
4896 LOperand* input = instr->value();
4897 Condition cc = masm()->CheckSmi(ToRegister(input));
4898 DeoptimizeIf(cc, instr->environment());
4899 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004900}
4901
4902
4903void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004904 Register input = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004905
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004906 __ movp(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004907
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004908 if (instr->hydrogen()->is_interval_check()) {
4909 InstanceType first;
4910 InstanceType last;
4911 instr->hydrogen()->GetCheckInterval(&first, &last);
4912
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004913 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4914 Immediate(static_cast<int8_t>(first)));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004915
4916 // If there is only one type in the interval check for equality.
4917 if (first == last) {
4918 DeoptimizeIf(not_equal, instr->environment());
4919 } else {
4920 DeoptimizeIf(below, instr->environment());
4921 // Omit check for the last type.
4922 if (last != LAST_TYPE) {
4923 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4924 Immediate(static_cast<int8_t>(last)));
4925 DeoptimizeIf(above, instr->environment());
4926 }
4927 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004928 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004929 uint8_t mask;
4930 uint8_t tag;
4931 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4932
4933 if (IsPowerOf2(mask)) {
4934 ASSERT(tag == 0 || IsPowerOf2(tag));
4935 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
4936 Immediate(mask));
4937 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment());
4938 } else {
4939 __ movzxbl(kScratchRegister,
4940 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset));
4941 __ andb(kScratchRegister, Immediate(mask));
4942 __ cmpb(kScratchRegister, Immediate(tag));
4943 DeoptimizeIf(not_equal, instr->environment());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004944 }
4945 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004946}
4947
4948
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004949void LCodeGen::DoCheckValue(LCheckValue* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004950 Register reg = ToRegister(instr->value());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004951 __ Cmp(reg, instr->hydrogen()->object().handle());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004952 DeoptimizeIf(not_equal, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004953}
4954
4955
danno@chromium.org59400602013-08-13 17:09:37 +00004956void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
4957 {
4958 PushSafepointRegistersScope scope(this);
4959 __ push(object);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004960 __ Set(rsi, 0);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00004961 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004962 RecordSafepointWithRegisters(
4963 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
4964
danno@chromium.org59400602013-08-13 17:09:37 +00004965 __ testq(rax, Immediate(kSmiTagMask));
4966 }
4967 DeoptimizeIf(zero, instr->environment());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004968}
4969
4970
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004971void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004972 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00004973 public:
4974 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
4975 : LDeferredCode(codegen), instr_(instr), object_(object) {
4976 SetExit(check_maps());
4977 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004978 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00004979 codegen()->DoDeferredInstanceMigration(instr_, object_);
4980 }
4981 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004982 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00004983 private:
4984 LCheckMaps* instr_;
4985 Label check_maps_;
4986 Register object_;
4987 };
4988
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00004989 if (instr->hydrogen()->CanOmitMapChecks()) return;
danno@chromium.org59400602013-08-13 17:09:37 +00004990
ulan@chromium.org56c14af2012-09-20 12:51:09 +00004991 LOperand* input = instr->value();
ager@chromium.org378b34e2011-01-28 08:04:38 +00004992 ASSERT(input->IsRegister());
4993 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00004994
danno@chromium.org59400602013-08-13 17:09:37 +00004995 DeferredCheckMaps* deferred = NULL;
4996 if (instr->hydrogen()->has_migration_target()) {
4997 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
4998 __ bind(deferred->check_maps());
4999 }
5000
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005001 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005002 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005003 for (int i = 0; i < map_set.size() - 1; i++) {
5004 Handle<Map> map = map_set.at(i).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005005 __ CompareMap(reg, map);
5006 __ j(equal, &success, Label::kNear);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005007 }
danno@chromium.org59400602013-08-13 17:09:37 +00005008
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005009 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005010 __ CompareMap(reg, map);
danno@chromium.org59400602013-08-13 17:09:37 +00005011 if (instr->hydrogen()->has_migration_target()) {
5012 __ j(not_equal, deferred->entry());
5013 } else {
5014 DeoptimizeIf(not_equal, instr->environment());
5015 }
5016
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005017 __ bind(&success);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005018}
5019
5020
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005021void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5022 XMMRegister value_reg = ToDoubleRegister(instr->unclamped());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005023 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005024 Register result_reg = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005025 __ ClampDoubleToUint8(value_reg, xmm_scratch, result_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005026}
5027
5028
5029void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5030 ASSERT(instr->unclamped()->Equals(instr->result()));
5031 Register value_reg = ToRegister(instr->result());
5032 __ ClampUint8(value_reg);
5033}
5034
5035
5036void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5037 ASSERT(instr->unclamped()->Equals(instr->result()));
5038 Register input_reg = ToRegister(instr->unclamped());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005039 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->temp_xmm());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005040 XMMRegister xmm_scratch = double_scratch0();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005041 Label is_smi, done, heap_number;
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005042 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear;
5043 __ JumpIfSmi(input_reg, &is_smi, dist);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005044
5045 // Check for heap number
5046 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
5047 factory()->heap_number_map());
5048 __ j(equal, &heap_number, Label::kNear);
5049
5050 // Check for undefined. Undefined is converted to zero for clamping
5051 // conversions.
5052 __ Cmp(input_reg, factory()->undefined_value());
5053 DeoptimizeIf(not_equal, instr->environment());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005054 __ movp(input_reg, Immediate(0));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005055 __ jmp(&done, Label::kNear);
5056
5057 // Heap number
5058 __ bind(&heap_number);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005059 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset));
5060 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00005061 __ jmp(&done, Label::kNear);
5062
5063 // smi
5064 __ bind(&is_smi);
5065 __ SmiToInteger32(input_reg, input_reg);
5066 __ ClampUint8(input_reg);
5067
5068 __ bind(&done);
5069}
5070
5071
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +00005072void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
5073 XMMRegister value_reg = ToDoubleRegister(instr->value());
5074 Register result_reg = ToRegister(instr->result());
5075 if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
5076 __ movq(result_reg, value_reg);
5077 __ shr(result_reg, Immediate(32));
5078 } else {
5079 __ movd(result_reg, value_reg);
5080 }
5081}
5082
5083
5084void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
5085 Register hi_reg = ToRegister(instr->hi());
5086 Register lo_reg = ToRegister(instr->lo());
5087 XMMRegister result_reg = ToDoubleRegister(instr->result());
5088 XMMRegister xmm_scratch = double_scratch0();
5089 __ movd(result_reg, hi_reg);
5090 __ psllq(result_reg, 32);
5091 __ movd(xmm_scratch, lo_reg);
5092 __ orps(result_reg, xmm_scratch);
5093}
5094
5095
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005096void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005097 class DeferredAllocate V8_FINAL : public LDeferredCode {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005098 public:
5099 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5100 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005101 virtual void Generate() V8_OVERRIDE {
5102 codegen()->DoDeferredAllocate(instr_);
5103 }
5104 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005105 private:
5106 LAllocate* instr_;
5107 };
5108
5109 DeferredAllocate* deferred =
5110 new(zone()) DeferredAllocate(this, instr);
5111
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005112 Register result = ToRegister(instr->result());
5113 Register temp = ToRegister(instr->temp());
5114
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005115 // Allocate memory for the object.
5116 AllocationFlags flags = TAG_OBJECT;
5117 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5118 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5119 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005120 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5121 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5122 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005123 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005124 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5125 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005126 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005127 }
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005128
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005129 if (instr->size()->IsConstantOperand()) {
5130 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
jkummerow@chromium.org50bb8682014-03-06 17:59:13 +00005131 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005132 } else {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00005133 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005134 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005135 }
5136
5137 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005138
5139 if (instr->hydrogen()->MustPrefillWithFiller()) {
5140 if (instr->size()->IsConstantOperand()) {
5141 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5142 __ movl(temp, Immediate((size / kPointerSize) - 1));
5143 } else {
5144 temp = ToRegister(instr->size());
5145 __ sar(temp, Immediate(kPointerSizeLog2));
5146 __ decl(temp);
5147 }
5148 Label loop;
5149 __ bind(&loop);
5150 __ Move(FieldOperand(result, temp, times_pointer_size, 0),
5151 isolate()->factory()->one_pointer_filler_map());
5152 __ decl(temp);
5153 __ j(not_zero, &loop);
5154 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005155}
5156
5157
5158void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005159 Register result = ToRegister(instr->result());
5160
5161 // TODO(3095996): Get rid of this. For now, we need to make the
5162 // result register contain a valid pointer because it is already
5163 // contained in the register pointer map.
danno@chromium.orgf005df62013-04-30 16:36:45 +00005164 __ Move(result, Smi::FromInt(0));
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005165
5166 PushSafepointRegistersScope scope(this);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005167 if (instr->size()->IsRegister()) {
5168 Register size = ToRegister(instr->size());
5169 ASSERT(!size.is(result));
5170 __ Integer32ToSmi(size, size);
5171 __ push(size);
5172 } else {
5173 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5174 __ Push(Smi::FromInt(size));
5175 }
5176
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005177 int flags = 0;
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005178 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5179 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5180 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005181 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005182 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5183 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005184 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005185 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005186 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005187 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005188 __ Push(Smi::FromInt(flags));
5189
5190 CallRuntimeFromDeferred(
5191 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00005192 __ StoreToSafepointRegisterSlot(result, rax);
5193}
5194
5195
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005197 ASSERT(ToRegister(instr->value()).is(rax));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 __ push(rax);
5199 CallRuntime(Runtime::kToFastProperties, 1, instr);
5200}
5201
5202
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005203void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005204 ASSERT(ToRegister(instr->context()).is(rsi));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005205 Label materialized;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005206 // Registers will be used as follows:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005207 // rcx = literals array.
5208 // rbx = regexp literal.
5209 // rax = regexp literal clone.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005210 int literal_offset =
5211 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005212 __ Move(rcx, instr->hydrogen()->literals());
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005213 __ movp(rbx, FieldOperand(rcx, literal_offset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005214 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005215 __ j(not_equal, &materialized, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005216
5217 // Create regexp literal using runtime function
5218 // Result will be in rax.
5219 __ push(rcx);
5220 __ Push(Smi::FromInt(instr->hydrogen()->literal_index()));
5221 __ Push(instr->hydrogen()->pattern());
5222 __ Push(instr->hydrogen()->flags());
5223 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005224 __ movp(rbx, rax);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005225
5226 __ bind(&materialized);
5227 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5228 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00005229 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005230 __ jmp(&allocated, Label::kNear);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005231
5232 __ bind(&runtime_allocate);
5233 __ push(rbx);
5234 __ Push(Smi::FromInt(size));
5235 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5236 __ pop(rbx);
5237
5238 __ bind(&allocated);
5239 // Copy the content into the newly allocated memory.
5240 // (Unroll copy loop once for better throughput).
5241 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005242 __ movp(rdx, FieldOperand(rbx, i));
5243 __ movp(rcx, FieldOperand(rbx, i + kPointerSize));
5244 __ movp(FieldOperand(rax, i), rdx);
5245 __ movp(FieldOperand(rax, i + kPointerSize), rcx);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005246 }
5247 if ((size % (2 * kPointerSize)) != 0) {
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005248 __ movp(rdx, FieldOperand(rbx, size - kPointerSize));
5249 __ movp(FieldOperand(rax, size - kPointerSize), rdx);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005250 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005251}
5252
5253
5254void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005255 ASSERT(ToRegister(instr->context()).is(rsi));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005256 // Use the fast case closure allocation code that allocates in new
5257 // space for nested functions that don't need literals cloning.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005258 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005259 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5260 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5261 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005262 __ Move(rbx, instr->hydrogen()->shared_info());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005263 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005264 } else {
5265 __ push(rsi);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005266 __ Push(instr->hydrogen()->shared_info());
5267 __ PushRoot(pretenure ? Heap::kTrueValueRootIndex :
5268 Heap::kFalseValueRootIndex);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005269 CallRuntime(Runtime::kNewClosure, 3, instr);
5270 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005271}
5272
5273
5274void LCodeGen::DoTypeof(LTypeof* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005275 ASSERT(ToRegister(instr->context()).is(rsi));
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005276 LOperand* input = instr->value();
danno@chromium.org160a7b02011-04-18 15:51:38 +00005277 EmitPushTaggedOperand(input);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005278 CallRuntime(Runtime::kTypeof, 1, instr);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005279}
5280
5281
danno@chromium.org160a7b02011-04-18 15:51:38 +00005282void LCodeGen::EmitPushTaggedOperand(LOperand* operand) {
5283 ASSERT(!operand->IsDoubleRegister());
5284 if (operand->IsConstantOperand()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00005285 __ Push(ToHandle(LConstantOperand::cast(operand)));
danno@chromium.org160a7b02011-04-18 15:51:38 +00005286 } else if (operand->IsRegister()) {
5287 __ push(ToRegister(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005288 } else {
danno@chromium.org160a7b02011-04-18 15:51:38 +00005289 __ push(ToOperand(operand));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005290 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005291}
5292
5293
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005294void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005295 Register input = ToRegister(instr->value());
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005296 Condition final_branch_condition = EmitTypeofIs(instr, input);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005297 if (final_branch_condition != no_condition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005298 EmitBranch(instr, final_branch_condition);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005299 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005300}
5301
5302
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005303Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) {
5304 Label* true_label = instr->TrueLabel(chunk_);
5305 Label* false_label = instr->FalseLabel(chunk_);
5306 Handle<String> type_name = instr->type_literal();
5307 int left_block = instr->TrueDestination(chunk_);
5308 int right_block = instr->FalseDestination(chunk_);
5309 int next_block = GetNextEmittedBlock();
5310
5311 Label::Distance true_distance = left_block == next_block ? Label::kNear
5312 : Label::kFar;
5313 Label::Distance false_distance = right_block == next_block ? Label::kNear
5314 : Label::kFar;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005315 Condition final_branch_condition = no_condition;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005316 if (type_name->Equals(heap()->number_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005317 __ JumpIfSmi(input, true_label, true_distance);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00005318 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset),
5319 Heap::kHeapNumberMapRootIndex);
5320
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005321 final_branch_condition = equal;
5322
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005323 } else if (type_name->Equals(heap()->string_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005324 __ JumpIfSmi(input, false_label, false_distance);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005325 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005326 __ j(above_equal, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005327 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5328 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005329 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005330
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005331 } else if (type_name->Equals(heap()->symbol_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005332 __ JumpIfSmi(input, false_label, false_distance);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005333 __ CmpObjectType(input, SYMBOL_TYPE, input);
5334 final_branch_condition = equal;
5335
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005336 } else if (type_name->Equals(heap()->boolean_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005337 __ CompareRoot(input, Heap::kTrueValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005338 __ j(equal, true_label, true_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005339 __ CompareRoot(input, Heap::kFalseValueRootIndex);
5340 final_branch_condition = equal;
5341
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005342 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005343 __ CompareRoot(input, Heap::kNullValueRootIndex);
5344 final_branch_condition = equal;
5345
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005346 } else if (type_name->Equals(heap()->undefined_string())) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005347 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005348 __ j(equal, true_label, true_distance);
5349 __ JumpIfSmi(input, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005350 // Check for undetectable objects => true.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005351 __ movp(input, FieldOperand(input, HeapObject::kMapOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005352 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5353 Immediate(1 << Map::kIsUndetectable));
5354 final_branch_condition = not_zero;
5355
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005356 } else if (type_name->Equals(heap()->function_string())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005357 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005358 __ JumpIfSmi(input, false_label, false_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005359 __ CmpObjectType(input, JS_FUNCTION_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005360 __ j(equal, true_label, true_distance);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005361 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE);
5362 final_branch_condition = equal;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005363
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005364 } else if (type_name->Equals(heap()->object_string())) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005365 __ JumpIfSmi(input, false_label, false_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005366 if (!FLAG_harmony_typeof) {
5367 __ CompareRoot(input, Heap::kNullValueRootIndex);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005368 __ j(equal, true_label, true_distance);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005369 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005370 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005371 __ j(below, false_label, false_distance);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005372 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005373 __ j(above, false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005374 // Check for undetectable objects => false.
5375 __ testb(FieldOperand(input, Map::kBitFieldOffset),
5376 Immediate(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005377 final_branch_condition = zero;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005378
5379 } else {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005380 __ jmp(false_label, false_distance);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00005381 }
5382
5383 return final_branch_condition;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005384}
5385
5386
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005387void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00005388 Register temp = ToRegister(instr->temp());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005389
5390 EmitIsConstructCall(temp);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005391 EmitBranch(instr, equal);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005392}
5393
5394
5395void LCodeGen::EmitIsConstructCall(Register temp) {
5396 // Get the frame pointer for the calling frame.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005397 __ movp(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005398
5399 // Skip the arguments adaptor frame if it exists.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005400 Label check_frame_marker;
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005401 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset),
5402 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00005403 __ j(not_equal, &check_frame_marker, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005404 __ movp(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005405
5406 // Check the marker in the calling frame.
5407 __ bind(&check_frame_marker);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00005408 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
5409 Smi::FromInt(StackFrame::CONSTRUCT));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005410}
5411
5412
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005413void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00005414 if (!info()->IsStub()) {
5415 // Ensure that we have enough space after the previous lazy-bailout
5416 // instruction for patching the code here.
5417 int current_pc = masm()->pc_offset();
5418 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5419 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5420 __ Nop(padding_size);
5421 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005422 }
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00005423 last_lazy_deopt_pc_ = masm()->pc_offset();
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005424}
5425
5426
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005427void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005428 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005429 ASSERT(instr->HasEnvironment());
5430 LEnvironment* env = instr->environment();
5431 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5432 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005433}
5434
5435
5436void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005437 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5438 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5439 // needed return address), even though the implementation of LAZY and EAGER is
5440 // now identical. When LAZY is eventually completely folded into EAGER, remove
5441 // the special case below.
5442 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5443 type = Deoptimizer::LAZY;
danno@chromium.orgaefd6072013-05-14 14:11:47 +00005444 }
danno@chromium.org59400602013-08-13 17:09:37 +00005445
5446 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005447 DeoptimizeIf(no_condition, instr->environment(), type);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005448}
5449
5450
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005451void LCodeGen::DoDummy(LDummy* instr) {
5452 // Nothing to see here, move on!
5453}
5454
5455
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005456void LCodeGen::DoDummyUse(LDummyUse* instr) {
5457 // Nothing to see here, move on!
5458}
5459
5460
ager@chromium.org04921a82011-06-27 13:21:41 +00005461void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005462 PushSafepointRegistersScope scope(this);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005463 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005464 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5465 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0);
5466 ASSERT(instr->HasEnvironment());
5467 LEnvironment* env = instr->environment();
5468 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005469}
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005470
ager@chromium.org04921a82011-06-27 13:21:41 +00005471
5472void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005473 class DeferredStackCheck V8_FINAL : public LDeferredCode {
ager@chromium.org04921a82011-06-27 13:21:41 +00005474 public:
5475 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5476 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005477 virtual void Generate() V8_OVERRIDE {
5478 codegen()->DoDeferredStackCheck(instr_);
5479 }
5480 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
ager@chromium.org04921a82011-06-27 13:21:41 +00005481 private:
5482 LStackCheck* instr_;
5483 };
5484
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005485 ASSERT(instr->HasEnvironment());
5486 LEnvironment* env = instr->environment();
5487 // There is no LLazyBailout instruction for stack-checks. We have to
5488 // prepare for lazy deoptimization explicitly here.
ager@chromium.org04921a82011-06-27 13:21:41 +00005489 if (instr->hydrogen()->is_function_entry()) {
5490 // Perform stack overflow check.
5491 Label done;
5492 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5493 __ j(above_equal, &done, Label::kNear);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005494
5495 ASSERT(instr->context()->IsRegister());
5496 ASSERT(ToRegister(instr->context()).is(rsi));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005497 CallCode(isolate()->builtins()->StackCheck(),
5498 RelocInfo::CODE_TARGET,
5499 instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005500 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00005501 __ bind(&done);
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005502 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5503 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
ager@chromium.org04921a82011-06-27 13:21:41 +00005504 } else {
5505 ASSERT(instr->hydrogen()->is_backwards_branch());
5506 // Perform stack overflow check if this goto needs it before jumping.
5507 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005508 new(zone()) DeferredStackCheck(this, instr);
ager@chromium.org04921a82011-06-27 13:21:41 +00005509 __ CompareRoot(rsp, Heap::kStackLimitRootIndex);
5510 __ j(below, deferred_stack_check->entry());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005511 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ager@chromium.org04921a82011-06-27 13:21:41 +00005512 __ bind(instr->done_label());
5513 deferred_stack_check->SetExit(instr->done_label());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005514 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5515 // Don't record a deoptimization index for the safepoint here.
5516 // This will be done explicitly when emitting call and the safepoint in
5517 // the deferred code.
ager@chromium.org04921a82011-06-27 13:21:41 +00005518 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005519}
5520
5521
5522void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005523 // This is a pseudo-instruction that ensures that the environment here is
5524 // properly registered for deoptimization and records the assembler's PC
5525 // offset.
5526 LEnvironment* environment = instr->environment();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00005527
5528 // If the environment were already registered, we would have no way of
5529 // backpatching it with the spill slot operands.
5530 ASSERT(!environment->HasBeenRegistered());
ricow@chromium.org27bf2882011-11-17 08:34:43 +00005531 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005532
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005533 GenerateOsrPrologue();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005534}
5535
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005536
5537void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005538 ASSERT(ToRegister(instr->context()).is(rsi));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005539 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
5540 DeoptimizeIf(equal, instr->environment());
5541
5542 Register null_value = rdi;
5543 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5544 __ cmpq(rax, null_value);
5545 DeoptimizeIf(equal, instr->environment());
5546
5547 Condition cc = masm()->CheckSmi(rax);
5548 DeoptimizeIf(cc, instr->environment());
5549
5550 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5551 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx);
5552 DeoptimizeIf(below_equal, instr->environment());
5553
5554 Label use_cache, call_runtime;
5555 __ CheckEnumCache(null_value, &call_runtime);
5556
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005557 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005558 __ jmp(&use_cache, Label::kNear);
5559
5560 // Get the set of properties to enumerate.
5561 __ bind(&call_runtime);
5562 __ push(rax);
5563 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5564
5565 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
5566 Heap::kMetaMapRootIndex);
5567 DeoptimizeIf(not_equal, instr->environment());
5568 __ bind(&use_cache);
5569}
5570
5571
5572void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5573 Register map = ToRegister(instr->map());
5574 Register result = ToRegister(instr->result());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005575 Label load_cache, done;
5576 __ EnumLength(result, map);
5577 __ Cmp(result, Smi::FromInt(0));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005578 __ j(not_equal, &load_cache, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005579 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005580 __ jmp(&done, Label::kNear);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005581 __ bind(&load_cache);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005582 __ LoadInstanceDescriptors(map, result);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005583 __ movp(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005584 FieldOperand(result, DescriptorArray::kEnumCacheOffset));
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005585 __ movp(result,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005586 FieldOperand(result, FixedArray::SizeFor(instr->idx())));
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005587 __ bind(&done);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005588 Condition cc = masm()->CheckSmi(result);
danno@chromium.org88aa0582012-03-23 15:11:57 +00005589 DeoptimizeIf(cc, instr->environment());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005590}
5591
5592
5593void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5594 Register object = ToRegister(instr->value());
5595 __ cmpq(ToRegister(instr->map()),
5596 FieldOperand(object, HeapObject::kMapOffset));
5597 DeoptimizeIf(not_equal, instr->environment());
5598}
5599
5600
5601void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5602 Register object = ToRegister(instr->object());
5603 Register index = ToRegister(instr->index());
5604
5605 Label out_of_object, done;
5606 __ SmiToInteger32(index, index);
5607 __ cmpl(index, Immediate(0));
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005608 __ j(less, &out_of_object, Label::kNear);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005609 __ movp(object, FieldOperand(object,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005610 index,
5611 times_pointer_size,
5612 JSObject::kHeaderSize));
5613 __ jmp(&done, Label::kNear);
5614
5615 __ bind(&out_of_object);
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005616 __ movp(object, FieldOperand(object, JSObject::kPropertiesOffset));
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005617 __ negl(index);
5618 // Index is now equal to out of object property index plus 1.
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00005619 __ movp(object, FieldOperand(object,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005620 index,
5621 times_pointer_size,
5622 FixedArray::kHeaderSize - kPointerSize));
5623 __ bind(&done);
5624}
5625
5626
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005627#undef __
5628
5629} } // namespace v8::internal
5630
5631#endif // V8_TARGET_ARCH_X64