blob: a2df23fc5a88bcd6278f2a46a3b70fc3944bb6bd [file] [log] [blame]
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00001// Copyright 2012 the V8 project authors. All rights reserved.7
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +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
30#include "mips/lithium-codegen-mips.h"
31#include "mips/lithium-gap-resolver-mips.h"
32#include "code-stubs.h"
33#include "stub-cache.h"
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000034#include "hydrogen-osr.h"
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000035
36namespace v8 {
37namespace internal {
38
39
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000040class SafepointGenerator V8_FINAL : public CallWrapper {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000041 public:
42 SafepointGenerator(LCodeGen* codegen,
43 LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +000044 Safepoint::DeoptMode mode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000045 : codegen_(codegen),
46 pointers_(pointers),
erikcorry0ad885c2011-11-21 13:51:57 +000047 deopt_mode_(mode) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000048 virtual ~SafepointGenerator() {}
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000049
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000050 virtual void BeforeCall(int call_size) const V8_OVERRIDE {}
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000051
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +000052 virtual void AfterCall() const V8_OVERRIDE {
erikcorry0ad885c2011-11-21 13:51:57 +000053 codegen_->RecordSafepoint(pointers_, deopt_mode_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000054 }
55
56 private:
57 LCodeGen* codegen_;
58 LPointerMap* pointers_;
erikcorry0ad885c2011-11-21 13:51:57 +000059 Safepoint::DeoptMode deopt_mode_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000060};
61
62
63#define __ masm()->
64
65bool LCodeGen::GenerateCode() {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000066 LPhase phase("Z_Code generation", chunk());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000067 ASSERT(is_unused());
68 status_ = GENERATING;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000069
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000070 // Open a frame scope to indicate that there is a frame on the stack. The
71 // NONE indicates that the scope shouldn't actually generate code to set up
72 // the frame (that is done in GeneratePrologue).
73 FrameScope frame_scope(masm_, StackFrame::NONE);
74
75 return GeneratePrologue() &&
76 GenerateBody() &&
77 GenerateDeferredCode() &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000078 GenerateDeoptJumpTable() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000079 GenerateSafepointTable();
80}
81
82
83void LCodeGen::FinishCode(Handle<Code> code) {
84 ASSERT(is_done());
85 code->set_stack_slots(GetStackSlotCount());
86 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
machenbach@chromium.orgddf38112013-12-04 09:42:52 +000087 RegisterDependentCodeForEmbeddedMaps(code);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000088 PopulateDeoptimizationData(code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000089 info()->CommitDependencies(code);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000090}
91
92
danno@chromium.org59400602013-08-13 17:09:37 +000093void LChunkBuilder::Abort(BailoutReason reason) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000094 info()->set_bailout_reason(reason);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000095 status_ = ABORTED;
96}
97
98
machenbach@chromium.orgf9841892013-11-25 12:01:13 +000099void LCodeGen::SaveCallerDoubles() {
100 ASSERT(info()->saves_caller_doubles());
101 ASSERT(NeedsEagerFrame());
102 Comment(";;; Save clobbered callee double registers");
103 int count = 0;
104 BitVector* doubles = chunk()->allocated_double_registers();
105 BitVector::Iterator save_iterator(doubles);
106 while (!save_iterator.Done()) {
107 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
108 MemOperand(sp, count * kDoubleSize));
109 save_iterator.Advance();
110 count++;
111 }
112}
113
114
115void LCodeGen::RestoreCallerDoubles() {
116 ASSERT(info()->saves_caller_doubles());
117 ASSERT(NeedsEagerFrame());
118 Comment(";;; Restore clobbered callee double registers");
119 BitVector* doubles = chunk()->allocated_double_registers();
120 BitVector::Iterator save_iterator(doubles);
121 int count = 0;
122 while (!save_iterator.Done()) {
123 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
124 MemOperand(sp, count * kDoubleSize));
125 save_iterator.Advance();
126 count++;
127 }
128}
129
130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000131bool LCodeGen::GeneratePrologue() {
132 ASSERT(is_generating());
133
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000134 if (info()->IsOptimizing()) {
135 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
danno@chromium.org129d3982012-07-25 15:01:47 +0000136
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000137#ifdef DEBUG
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000138 if (strlen(FLAG_stop_at) > 0 &&
139 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
140 __ stop("stop_at");
141 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000142#endif
143
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000144 // a1: Callee's JS function.
145 // cp: Callee's context.
146 // fp: Caller's frame pointer.
147 // lr: Caller's pc.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000148
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000149 // Classic mode functions and builtins need to replace the receiver with the
150 // global proxy when called as functions (without an explicit receiver
151 // object).
152 if (info_->this_has_uses() &&
153 info_->is_classic_mode() &&
154 !info_->is_native()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000155 Label ok;
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000156 int receiver_offset = info_->scope()->num_parameters() * kPointerSize;
157 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
158 __ lw(a2, MemOperand(sp, receiver_offset));
159 __ Branch(&ok, ne, a2, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000160
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000161 __ lw(a2, GlobalObjectOperand());
162 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
163
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000164 __ sw(a2, MemOperand(sp, receiver_offset));
machenbach@chromium.orge31286d2014-01-15 10:29:52 +0000165
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000166 __ bind(&ok);
167 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000168 }
169
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000170 info()->set_prologue_offset(masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000171 if (NeedsEagerFrame()) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000172 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000173 frame_is_built_ = true;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000174 info_->AddNoFrameRange(0, masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000175 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000176
177 // Reserve space for the stack slots needed by the code.
178 int slots = GetStackSlotCount();
179 if (slots > 0) {
180 if (FLAG_debug_code) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000181 __ Subu(sp, sp, Operand(slots * kPointerSize));
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000182 __ Push(a0, a1);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000183 __ Addu(a0, sp, Operand(slots * kPointerSize));
184 __ li(a1, Operand(kSlotsZapValue));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000185 Label loop;
186 __ bind(&loop);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000187 __ Subu(a0, a0, Operand(kPointerSize));
188 __ sw(a1, MemOperand(a0, 2 * kPointerSize));
189 __ Branch(&loop, ne, a0, Operand(sp));
machenbach@chromium.org6f1040e2014-02-04 07:54:22 +0000190 __ Pop(a0, a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000191 } else {
192 __ Subu(sp, sp, Operand(slots * kPointerSize));
193 }
194 }
195
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000196 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000197 SaveCallerDoubles();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000198 }
199
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000200 // Possibly allocate a local context.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000201 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000202 if (heap_slots > 0) {
203 Comment(";;; Allocate local context");
204 // Argument to NewContext is the function, which is in a1.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000205 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
206 FastNewContextStub stub(heap_slots);
207 __ CallStub(&stub);
208 } else {
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000209 __ push(a1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000210 __ CallRuntime(Runtime::kNewFunctionContext, 1);
211 }
erikcorry0ad885c2011-11-21 13:51:57 +0000212 RecordSafepoint(Safepoint::kNoLazyDeopt);
palfia@homejinni.comcc96b0e2014-01-23 17:24:54 +0000213 // Context is returned in both v0. It replaces the context passed to us.
214 // It's saved in the stack and kept live in cp.
215 __ mov(cp, v0);
216 __ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000217 // Copy any necessary parameters into the context.
218 int num_parameters = scope()->num_parameters();
219 for (int i = 0; i < num_parameters; i++) {
220 Variable* var = scope()->parameter(i);
221 if (var->IsContextSlot()) {
222 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
223 (num_parameters - 1 - i) * kPointerSize;
224 // Load parameter from stack.
225 __ lw(a0, MemOperand(fp, parameter_offset));
226 // Store it in the context.
227 MemOperand target = ContextOperand(cp, var->index());
228 __ sw(a0, target);
229 // Update the write barrier. This clobbers a3 and a0.
230 __ RecordWriteContextSlot(
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000231 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000232 }
233 }
234 Comment(";;; End allocate local context");
235 }
236
237 // Trace the call.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000238 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000239 // We have not executed any compiled code yet, so cp still holds the
240 // incoming context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000241 __ CallRuntime(Runtime::kTraceEnter, 0);
242 }
243 return !is_aborted();
244}
245
246
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000247void LCodeGen::GenerateOsrPrologue() {
248 // Generate the OSR entry prologue at the first unknown OSR value, or if there
249 // are none, at the OSR entrypoint instruction.
250 if (osr_pc_offset_ >= 0) return;
251
252 osr_pc_offset_ = masm()->pc_offset();
253
254 // Adjust the frame size, subsuming the unoptimized frame into the
255 // optimized frame.
256 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
257 ASSERT(slots >= 0);
258 __ Subu(sp, sp, Operand(slots * kPointerSize));
259}
260
261
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000262bool LCodeGen::GenerateDeferredCode() {
263 ASSERT(is_generating());
264 if (deferred_.length() > 0) {
265 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
266 LDeferredCode* code = deferred_[i];
danno@chromium.org59400602013-08-13 17:09:37 +0000267
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000268 HValue* value =
269 instructions_->at(code->instruction_index())->hydrogen_value();
270 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000271
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000272 Comment(";;; <@%d,#%d> "
273 "-------------------- Deferred %s --------------------",
274 code->instruction_index(),
275 code->instr()->hydrogen_value()->id(),
276 code->instr()->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000277 __ bind(code->entry());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000278 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000279 Comment(";;; Build frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000280 ASSERT(!frame_is_built_);
281 ASSERT(info()->IsStub());
282 frame_is_built_ = true;
283 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
284 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
285 __ push(scratch0());
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000286 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000287 Comment(";;; Deferred code");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000288 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000289 code->Generate();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000290 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000291 Comment(";;; Destroy frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000292 ASSERT(frame_is_built_);
293 __ pop(at);
294 __ MultiPop(cp.bit() | fp.bit() | ra.bit());
295 frame_is_built_ = false;
296 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000297 __ jmp(code->exit());
298 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000299 }
300 // Deferred code is the last part of the instruction sequence. Mark
301 // the generated code as done unless we bailed out.
302 if (!is_aborted()) status_ = DONE;
303 return !is_aborted();
304}
305
306
307bool LCodeGen::GenerateDeoptJumpTable() {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000308 if (deopt_jump_table_.length() > 0) {
309 Comment(";;; -------------------- Jump table --------------------");
310 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000311 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000312 Label table_start;
313 __ bind(&table_start);
danno@chromium.org169691d2013-07-15 08:01:13 +0000314 Label needs_frame;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000315 for (int i = 0; i < deopt_jump_table_.length(); i++) {
316 __ bind(&deopt_jump_table_[i].label);
317 Address entry = deopt_jump_table_[i].address;
palfia@homejinni.com04109732013-05-15 09:50:32 +0000318 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000319 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000320 if (id == Deoptimizer::kNotDeoptimizationEntry) {
321 Comment(";;; jump table entry %d.", i);
322 } else {
323 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
324 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000325 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
326 if (deopt_jump_table_[i].needs_frame) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000327 ASSERT(!info()->saves_caller_doubles());
danno@chromium.org169691d2013-07-15 08:01:13 +0000328 if (needs_frame.is_bound()) {
329 __ Branch(&needs_frame);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000330 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000331 __ bind(&needs_frame);
332 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
333 // This variant of deopt can only be used with stubs. Since we don't
334 // have a function pointer to install in the stack frame that we're
335 // building, install a special marker there instead.
336 ASSERT(info()->IsStub());
337 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
338 __ push(scratch0());
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000339 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
danno@chromium.org169691d2013-07-15 08:01:13 +0000340 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000341 }
342 } else {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000343 if (info()->saves_caller_doubles()) {
344 ASSERT(info()->IsStub());
345 RestoreCallerDoubles();
346 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000347 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000348 }
349 }
350 __ RecordComment("]");
351
352 // The deoptimization jump table is the last part of the instruction
353 // sequence. Mark the generated code as done unless we bailed out.
354 if (!is_aborted()) status_ = DONE;
355 return !is_aborted();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000356}
357
358
359bool LCodeGen::GenerateSafepointTable() {
360 ASSERT(is_done());
361 safepoints_.Emit(masm(), GetStackSlotCount());
362 return !is_aborted();
363}
364
365
366Register LCodeGen::ToRegister(int index) const {
367 return Register::FromAllocationIndex(index);
368}
369
370
371DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
372 return DoubleRegister::FromAllocationIndex(index);
373}
374
375
376Register LCodeGen::ToRegister(LOperand* op) const {
377 ASSERT(op->IsRegister());
378 return ToRegister(op->index());
379}
380
381
382Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
383 if (op->IsRegister()) {
384 return ToRegister(op->index());
385 } else if (op->IsConstantOperand()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000386 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000387 HConstant* constant = chunk_->LookupConstant(const_op);
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000388 Handle<Object> literal = constant->handle(isolate());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000389 Representation r = chunk_->LookupLiteralRepresentation(const_op);
390 if (r.IsInteger32()) {
391 ASSERT(literal->IsNumber());
392 __ li(scratch, Operand(static_cast<int32_t>(literal->Number())));
palfia@homejinni.com09b34542013-08-01 08:07:42 +0000393 } else if (r.IsSmi()) {
394 ASSERT(constant->HasSmiValue());
395 __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000396 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000397 Abort(kEmitLoadRegisterUnsupportedDoubleImmediate);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000398 } else {
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000399 ASSERT(r.IsSmiOrTagged());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000400 __ li(scratch, literal);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000401 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000402 return scratch;
403 } else if (op->IsStackSlot() || op->IsArgument()) {
404 __ lw(scratch, ToMemOperand(op));
405 return scratch;
406 }
407 UNREACHABLE();
408 return scratch;
409}
410
411
412DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
413 ASSERT(op->IsDoubleRegister());
414 return ToDoubleRegister(op->index());
415}
416
417
418DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
419 FloatRegister flt_scratch,
420 DoubleRegister dbl_scratch) {
421 if (op->IsDoubleRegister()) {
422 return ToDoubleRegister(op->index());
423 } else if (op->IsConstantOperand()) {
424 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000425 HConstant* constant = chunk_->LookupConstant(const_op);
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000426 Handle<Object> literal = constant->handle(isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000427 Representation r = chunk_->LookupLiteralRepresentation(const_op);
428 if (r.IsInteger32()) {
429 ASSERT(literal->IsNumber());
430 __ li(at, Operand(static_cast<int32_t>(literal->Number())));
431 __ mtc1(at, flt_scratch);
432 __ cvt_d_w(dbl_scratch, flt_scratch);
433 return dbl_scratch;
434 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000435 Abort(kUnsupportedDoubleImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000436 } else if (r.IsTagged()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000437 Abort(kUnsupportedTaggedImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000438 }
439 } else if (op->IsStackSlot() || op->IsArgument()) {
440 MemOperand mem_op = ToMemOperand(op);
441 __ ldc1(dbl_scratch, mem_op);
442 return dbl_scratch;
443 }
444 UNREACHABLE();
445 return dbl_scratch;
446}
447
448
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000449Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000450 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000451 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000452 return constant->handle(isolate());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000453}
454
455
456bool LCodeGen::IsInteger32(LConstantOperand* op) const {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000457 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000458}
459
460
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000461bool LCodeGen::IsSmi(LConstantOperand* op) const {
462 return chunk_->LookupLiteralRepresentation(op).IsSmi();
463}
464
465
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000466int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
467 return ToRepresentation(op, Representation::Integer32());
468}
469
470
471int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
472 const Representation& r) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000473 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000474 int32_t value = constant->Integer32Value();
475 if (r.IsInteger32()) return value;
476 ASSERT(r.IsSmiOrTagged());
477 return reinterpret_cast<int32_t>(Smi::FromInt(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000478}
479
480
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000481Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
482 HConstant* constant = chunk_->LookupConstant(op);
483 return Smi::FromInt(constant->Integer32Value());
484}
485
486
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000487double LCodeGen::ToDouble(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000488 HConstant* constant = chunk_->LookupConstant(op);
489 ASSERT(constant->HasDoubleValue());
490 return constant->DoubleValue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000491}
492
493
494Operand LCodeGen::ToOperand(LOperand* op) {
495 if (op->IsConstantOperand()) {
496 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000497 HConstant* constant = chunk()->LookupConstant(const_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000498 Representation r = chunk_->LookupLiteralRepresentation(const_op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000499 if (r.IsSmi()) {
500 ASSERT(constant->HasSmiValue());
501 return Operand(Smi::FromInt(constant->Integer32Value()));
502 } else if (r.IsInteger32()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000503 ASSERT(constant->HasInteger32Value());
504 return Operand(constant->Integer32Value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000505 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000506 Abort(kToOperandUnsupportedDoubleImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000507 }
508 ASSERT(r.IsTagged());
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000509 return Operand(constant->handle(isolate()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000510 } else if (op->IsRegister()) {
511 return Operand(ToRegister(op));
512 } else if (op->IsDoubleRegister()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000513 Abort(kToOperandIsDoubleRegisterUnimplemented);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000514 return Operand(0);
515 }
516 // Stack slots not implemented, use ToMemOperand instead.
517 UNREACHABLE();
518 return Operand(0);
519}
520
521
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000522static int ArgumentsOffsetWithoutFrame(int index) {
523 ASSERT(index < 0);
524 return -(index + 1) * kPointerSize;
525}
526
527
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000528MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
529 ASSERT(!op->IsRegister());
530 ASSERT(!op->IsDoubleRegister());
531 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000532 if (NeedsEagerFrame()) {
533 return MemOperand(fp, StackSlotOffset(op->index()));
534 } else {
535 // Retrieve parameter without eager stack-frame relative to the
536 // stack-pointer.
537 return MemOperand(sp, ArgumentsOffsetWithoutFrame(op->index()));
538 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000539}
540
541
542MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
543 ASSERT(op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000544 if (NeedsEagerFrame()) {
545 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
546 } else {
547 // Retrieve parameter without eager stack-frame relative to the
548 // stack-pointer.
549 return MemOperand(
550 sp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize);
551 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000552}
553
554
555void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000556 Translation* translation) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000557 if (environment == NULL) return;
558
559 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000560 int translation_size = environment->translation_size();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000561 // The output frame height does not include the parameters.
562 int height = translation_size - environment->parameter_count();
563
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000564 WriteTranslation(environment->outer(), translation);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000565 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000566 !info()->closure().is_identical_to(environment->closure());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000567 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000568 ? DefineDeoptimizationLiteral(environment->closure())
569 : Translation::kSelfLiteralId;
570
ulan@chromium.org812308e2012-02-29 15:58:45 +0000571 switch (environment->frame_type()) {
572 case JS_FUNCTION:
573 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
574 break;
575 case JS_CONSTRUCT:
576 translation->BeginConstructStubFrame(closure_id, translation_size);
577 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000578 case JS_GETTER:
579 ASSERT(translation_size == 1);
580 ASSERT(height == 0);
581 translation->BeginGetterStubFrame(closure_id);
582 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000583 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000584 ASSERT(translation_size == 2);
585 ASSERT(height == 0);
586 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000587 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000588 case STUB:
589 translation->BeginCompiledStubFrame();
590 break;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000591 case ARGUMENTS_ADAPTOR:
592 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
593 break;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000594 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000595
danno@chromium.org59400602013-08-13 17:09:37 +0000596 int object_index = 0;
597 int dematerialized_index = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000598 for (int i = 0; i < translation_size; ++i) {
599 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000600 AddToTranslation(environment,
601 translation,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000602 value,
603 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000604 environment->HasUint32ValueAt(i),
605 &object_index,
606 &dematerialized_index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000607 }
608}
609
610
danno@chromium.org59400602013-08-13 17:09:37 +0000611void LCodeGen::AddToTranslation(LEnvironment* environment,
612 Translation* translation,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000613 LOperand* op,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000614 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000615 bool is_uint32,
616 int* object_index_pointer,
617 int* dematerialized_index_pointer) {
618 if (op == LEnvironment::materialization_marker()) {
619 int object_index = (*object_index_pointer)++;
620 if (environment->ObjectIsDuplicateAt(object_index)) {
621 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
622 translation->DuplicateObject(dupe_of);
623 return;
624 }
625 int object_length = environment->ObjectLengthAt(object_index);
626 if (environment->ObjectIsArgumentsAt(object_index)) {
627 translation->BeginArgumentsObject(object_length);
628 } else {
629 translation->BeginCapturedObject(object_length);
630 }
631 int dematerialized_index = *dematerialized_index_pointer;
632 int env_offset = environment->translation_size() + dematerialized_index;
633 *dematerialized_index_pointer += object_length;
634 for (int i = 0; i < object_length; ++i) {
635 LOperand* value = environment->values()->at(env_offset + i);
636 AddToTranslation(environment,
637 translation,
638 value,
639 environment->HasTaggedValueAt(env_offset + i),
640 environment->HasUint32ValueAt(env_offset + i),
641 object_index_pointer,
642 dematerialized_index_pointer);
643 }
644 return;
645 }
646
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000647 if (op->IsStackSlot()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000648 if (is_tagged) {
649 translation->StoreStackSlot(op->index());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000650 } else if (is_uint32) {
651 translation->StoreUint32StackSlot(op->index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000652 } else {
653 translation->StoreInt32StackSlot(op->index());
654 }
655 } else if (op->IsDoubleStackSlot()) {
656 translation->StoreDoubleStackSlot(op->index());
657 } else if (op->IsArgument()) {
658 ASSERT(is_tagged);
659 int src_index = GetStackSlotCount() + op->index();
660 translation->StoreStackSlot(src_index);
661 } else if (op->IsRegister()) {
662 Register reg = ToRegister(op);
663 if (is_tagged) {
664 translation->StoreRegister(reg);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000665 } else if (is_uint32) {
666 translation->StoreUint32Register(reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 } else {
668 translation->StoreInt32Register(reg);
669 }
670 } else if (op->IsDoubleRegister()) {
671 DoubleRegister reg = ToDoubleRegister(op);
672 translation->StoreDoubleRegister(reg);
673 } else if (op->IsConstantOperand()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000674 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000675 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000676 translation->StoreLiteral(src_index);
677 } else {
678 UNREACHABLE();
679 }
680}
681
682
683void LCodeGen::CallCode(Handle<Code> code,
684 RelocInfo::Mode mode,
685 LInstruction* instr) {
686 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
687}
688
689
690void LCodeGen::CallCodeGeneric(Handle<Code> code,
691 RelocInfo::Mode mode,
692 LInstruction* instr,
693 SafepointMode safepoint_mode) {
694 ASSERT(instr != NULL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000695 __ Call(code, mode);
erikcorry0ad885c2011-11-21 13:51:57 +0000696 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697}
698
699
700void LCodeGen::CallRuntime(const Runtime::Function* function,
701 int num_arguments,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000702 LInstruction* instr,
703 SaveFPRegsMode save_doubles) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 ASSERT(instr != NULL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000705
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000706 __ CallRuntime(function, num_arguments, save_doubles);
707
erikcorry0ad885c2011-11-21 13:51:57 +0000708 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000709}
710
711
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000712void LCodeGen::LoadContextFromDeferred(LOperand* context) {
713 if (context->IsRegister()) {
714 __ Move(cp, ToRegister(context));
715 } else if (context->IsStackSlot()) {
716 __ lw(cp, ToMemOperand(context));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000717 } else if (context->IsConstantOperand()) {
718 HConstant* constant =
719 chunk_->LookupConstant(LConstantOperand::cast(context));
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000720 __ li(cp, Handle<Object>::cast(constant->handle(isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000721 } else {
722 UNREACHABLE();
723 }
724}
725
726
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000727void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
728 int argc,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000729 LInstruction* instr,
730 LOperand* context) {
731 LoadContextFromDeferred(context);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000732 __ CallRuntimeSaveDoubles(id);
733 RecordSafepointWithRegisters(
erikcorry0ad885c2011-11-21 13:51:57 +0000734 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000735}
736
737
erikcorry0ad885c2011-11-21 13:51:57 +0000738void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
739 Safepoint::DeoptMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000740 if (!environment->HasBeenRegistered()) {
741 // Physical stack frame layout:
742 // -x ............. -4 0 ..................................... y
743 // [incoming arguments] [spill slots] [pushed outgoing arguments]
744
745 // Layout of the environment:
746 // 0 ..................................................... size-1
747 // [parameters] [locals] [expression stack including arguments]
748
749 // Layout of the translation:
750 // 0 ........................................................ size - 1 + 4
751 // [expression stack including arguments] [locals] [4 words] [parameters]
752 // |>------------ translation_size ------------<|
753
754 int frame_count = 0;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000755 int jsframe_count = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
757 ++frame_count;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000758 if (e->frame_type() == JS_FUNCTION) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000759 ++jsframe_count;
760 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000761 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000762 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000763 WriteTranslation(environment, &translation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000764 int deoptimization_index = deoptimizations_.length();
erikcorry0ad885c2011-11-21 13:51:57 +0000765 int pc_offset = masm()->pc_offset();
766 environment->Register(deoptimization_index,
767 translation.index(),
768 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000769 deoptimizations_.Add(environment, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000770 }
771}
772
773
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000774void LCodeGen::DeoptimizeIf(Condition condition,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000775 LEnvironment* environment,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000776 Deoptimizer::BailoutType bailout_type,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000777 Register src1,
778 const Operand& src2) {
erikcorry0ad885c2011-11-21 13:51:57 +0000779 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000780 ASSERT(environment->HasBeenRegistered());
781 int id = environment->deoptimization_index();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000782 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000783 Address entry =
784 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000785 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +0000786 Abort(kBailoutWasNotPrepared);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000787 return;
788 }
789
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000790 if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
791 Register scratch = scratch0();
792 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
793 Label no_deopt;
794 __ Push(a1, scratch);
795 __ li(scratch, Operand(count));
796 __ lw(a1, MemOperand(scratch));
797 __ Subu(a1, a1, Operand(1));
798 __ Branch(&no_deopt, ne, a1, Operand(zero_reg));
799 __ li(a1, Operand(FLAG_deopt_every_n_times));
800 __ sw(a1, MemOperand(scratch));
801 __ Pop(a1, scratch);
802
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000803 __ Call(entry, RelocInfo::RUNTIME_ENTRY);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000804 __ bind(&no_deopt);
805 __ sw(a1, MemOperand(scratch));
806 __ Pop(a1, scratch);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000807 }
808
danno@chromium.org59400602013-08-13 17:09:37 +0000809 if (info()->ShouldTrapOnDeopt()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000810 Label skip;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000811 if (condition != al) {
812 __ Branch(&skip, NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000813 }
814 __ stop("trap_on_deopt");
815 __ bind(&skip);
816 }
817
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000818 ASSERT(info()->IsStub() || frame_is_built_);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000819 // Go through jump table if we need to handle condition, build frame, or
820 // restore caller doubles.
821 if (condition == al && frame_is_built_ &&
822 !info()->saves_caller_doubles()) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000823 __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000824 } else {
825 // We often have several deopts to the same entry, reuse the last
826 // jump entry if this is the case.
827 if (deopt_jump_table_.is_empty() ||
828 (deopt_jump_table_.last().address != entry) ||
palfia@homejinni.com04109732013-05-15 09:50:32 +0000829 (deopt_jump_table_.last().bailout_type != bailout_type) ||
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000830 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000831 Deoptimizer::JumpTableEntry table_entry(entry,
832 bailout_type,
833 !frame_is_built_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000834 deopt_jump_table_.Add(table_entry, zone());
835 }
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000836 __ Branch(&deopt_jump_table_.last().label, condition, src1, src2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000837 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000838}
839
840
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000841void LCodeGen::DeoptimizeIf(Condition condition,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000842 LEnvironment* environment,
843 Register src1,
844 const Operand& src2) {
845 Deoptimizer::BailoutType bailout_type = info()->IsStub()
846 ? Deoptimizer::LAZY
847 : Deoptimizer::EAGER;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000848 DeoptimizeIf(condition, environment, bailout_type, src1, src2);
palfia@homejinni.com04109732013-05-15 09:50:32 +0000849}
850
851
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000852void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
853 int length = deoptimizations_.length();
854 if (length == 0) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000855 Handle<DeoptimizationInputData> data =
856 factory()->NewDeoptimizationInputData(length, TENURED);
857
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000858 Handle<ByteArray> translations =
859 translations_.CreateByteArray(isolate()->factory());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000860 data->SetTranslationByteArray(*translations);
861 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
862
863 Handle<FixedArray> literals =
864 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000865 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000866 for (int i = 0; i < deoptimization_literals_.length(); i++) {
867 literals->set(i, *deoptimization_literals_[i]);
868 }
869 data->SetLiteralArray(*literals);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000870 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000871
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000872 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000873 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
874
875 // Populate the deoptimization entries.
876 for (int i = 0; i < length; i++) {
877 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000878 data->SetAstId(i, env->ast_id());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000879 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
880 data->SetArgumentsStackHeight(i,
881 Smi::FromInt(env->arguments_stack_height()));
erikcorry0ad885c2011-11-21 13:51:57 +0000882 data->SetPc(i, Smi::FromInt(env->pc_offset()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000883 }
884 code->set_deoptimization_data(*data);
885}
886
887
888int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
889 int result = deoptimization_literals_.length();
890 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
891 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
892 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000893 deoptimization_literals_.Add(literal, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000894 return result;
895}
896
897
898void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
899 ASSERT(deoptimization_literals_.length() == 0);
900
901 const ZoneList<Handle<JSFunction> >* inlined_closures =
902 chunk()->inlined_closures();
903
904 for (int i = 0, length = inlined_closures->length();
905 i < length;
906 i++) {
907 DefineDeoptimizationLiteral(inlined_closures->at(i));
908 }
909
910 inlined_function_count_ = deoptimization_literals_.length();
911}
912
913
erikcorry0ad885c2011-11-21 13:51:57 +0000914void LCodeGen::RecordSafepointWithLazyDeopt(
915 LInstruction* instr, SafepointMode safepoint_mode) {
916 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
917 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
918 } else {
919 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
920 RecordSafepointWithRegisters(
921 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
922 }
923}
924
925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000926void LCodeGen::RecordSafepoint(
927 LPointerMap* pointers,
928 Safepoint::Kind kind,
929 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000930 Safepoint::DeoptMode deopt_mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000931 ASSERT(expected_safepoint_kind_ == kind);
932
933 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
934 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
erikcorry0ad885c2011-11-21 13:51:57 +0000935 kind, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000936 for (int i = 0; i < operands->length(); i++) {
937 LOperand* pointer = operands->at(i);
938 if (pointer->IsStackSlot()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000939 safepoint.DefinePointerSlot(pointer->index(), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000940 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000941 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000942 }
943 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000944}
945
946
947void LCodeGen::RecordSafepoint(LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +0000948 Safepoint::DeoptMode deopt_mode) {
949 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000950}
951
952
erikcorry0ad885c2011-11-21 13:51:57 +0000953void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000954 LPointerMap empty_pointers(zone());
erikcorry0ad885c2011-11-21 13:51:57 +0000955 RecordSafepoint(&empty_pointers, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000956}
957
958
959void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
960 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000961 Safepoint::DeoptMode deopt_mode) {
962 RecordSafepoint(
963 pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000964}
965
966
967void LCodeGen::RecordSafepointWithRegistersAndDoubles(
968 LPointerMap* pointers,
969 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000970 Safepoint::DeoptMode deopt_mode) {
971 RecordSafepoint(
972 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000973}
974
975
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000976void LCodeGen::RecordAndWritePosition(int position) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000977 if (position == RelocInfo::kNoPosition) return;
978 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000979 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +0000980}
981
982
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000983static const char* LabelType(LLabel* label) {
984 if (label->is_loop_header()) return " (loop header)";
985 if (label->is_osr_entry()) return " (OSR entry)";
986 return "";
987}
988
989
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000990void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000991 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
992 current_instruction_,
993 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000994 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000995 LabelType(label));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000996 __ bind(label->label());
997 current_block_ = label->block_id();
998 DoGap(label);
999}
1000
1001
1002void LCodeGen::DoParallelMove(LParallelMove* move) {
1003 resolver_.Resolve(move);
1004}
1005
1006
1007void LCodeGen::DoGap(LGap* gap) {
1008 for (int i = LGap::FIRST_INNER_POSITION;
1009 i <= LGap::LAST_INNER_POSITION;
1010 i++) {
1011 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1012 LParallelMove* move = gap->GetParallelMove(inner_pos);
1013 if (move != NULL) DoParallelMove(move);
1014 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001015}
1016
1017
1018void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1019 DoGap(instr);
1020}
1021
1022
1023void LCodeGen::DoParameter(LParameter* instr) {
1024 // Nothing to do.
1025}
1026
1027
1028void LCodeGen::DoCallStub(LCallStub* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001029 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001030 ASSERT(ToRegister(instr->result()).is(v0));
1031 switch (instr->hydrogen()->major_key()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001032 case CodeStub::RegExpExec: {
1033 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001034 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001035 break;
1036 }
1037 case CodeStub::SubString: {
1038 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001039 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001040 break;
1041 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001042 case CodeStub::StringCompare: {
1043 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001044 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001045 break;
1046 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001047 default:
1048 UNREACHABLE();
1049 }
1050}
1051
1052
1053void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001054 GenerateOsrPrologue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001055}
1056
1057
1058void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001059 HMod* hmod = instr->hydrogen();
1060 HValue* left = hmod->left();
1061 HValue* right = hmod->right();
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00001062 if (hmod->RightIsPowerOf2()) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001063 const Register left_reg = ToRegister(instr->left());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001064 const Register result_reg = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001065
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001066 // Note: The code below even works when right contains kMinInt.
1067 int32_t divisor = Abs(right->GetInteger32Constant());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001068
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001069 Label left_is_not_negative, done;
1070 if (left->CanBeNegative()) {
danno@chromium.orgc16e8282013-08-12 16:17:40 +00001071 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT,
1072 &left_is_not_negative, ge, left_reg, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001073 __ subu(result_reg, zero_reg, left_reg);
1074 __ And(result_reg, result_reg, divisor - 1);
1075 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1076 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1077 }
1078 __ Branch(USE_DELAY_SLOT, &done);
1079 __ subu(result_reg, zero_reg, result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001080 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001081
1082 __ bind(&left_is_not_negative);
danno@chromium.orgc16e8282013-08-12 16:17:40 +00001083 __ And(result_reg, left_reg, divisor - 1);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001084 __ bind(&done);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001085 } else {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001086 const Register scratch = scratch0();
1087 const Register left_reg = ToRegister(instr->left());
1088 const Register result_reg = ToRegister(instr->result());
1089
1090 // div runs in the background while we check for special cases.
1091 Register right_reg = EmitLoadRegister(instr->right(), scratch);
1092 __ div(left_reg, right_reg);
1093
1094 Label done;
1095 // Check for x % 0, we have to deopt in this case because we can't return a
1096 // NaN.
1097 if (right->CanBeZero()) {
1098 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001099 }
1100
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001101 // Check for kMinInt % -1, we have to deopt if we care about -0, because we
1102 // can't return that.
1103 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001104 Label left_not_min_int;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001105 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt));
1106 // TODO(svenpanne) Don't deopt when we don't care about -0.
1107 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001108 __ bind(&left_not_min_int);
1109 }
1110
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001111 // TODO(svenpanne) Only emit the test/deopt if we have to.
1112 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg));
1113 __ mfhi(result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001114
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001115 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1116 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001117 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001118 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001119 }
1120}
1121
1122
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001123void LCodeGen::EmitSignedIntegerDivisionByConstant(
1124 Register result,
1125 Register dividend,
1126 int32_t divisor,
1127 Register remainder,
1128 Register scratch,
1129 LEnvironment* environment) {
1130 ASSERT(!AreAliased(dividend, scratch, at, no_reg));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001131
1132 uint32_t divisor_abs = abs(divisor);
1133
1134 int32_t power_of_2_factor =
1135 CompilerIntrinsics::CountTrailingZeros(divisor_abs);
1136
1137 switch (divisor_abs) {
1138 case 0:
1139 DeoptimizeIf(al, environment);
1140 return;
1141
1142 case 1:
1143 if (divisor > 0) {
1144 __ Move(result, dividend);
1145 } else {
1146 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch);
1147 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg));
1148 }
1149 // Compute the remainder.
1150 __ Move(remainder, zero_reg);
1151 return;
1152
1153 default:
1154 if (IsPowerOf2(divisor_abs)) {
1155 // Branch and condition free code for integer division by a power
1156 // of two.
1157 int32_t power = WhichPowerOf2(divisor_abs);
1158 if (power > 1) {
1159 __ sra(scratch, dividend, power - 1);
1160 }
1161 __ srl(scratch, scratch, 32 - power);
1162 __ Addu(scratch, dividend, Operand(scratch));
1163 __ sra(result, scratch, power);
1164 // Negate if necessary.
1165 // We don't need to check for overflow because the case '-1' is
1166 // handled separately.
1167 if (divisor < 0) {
1168 ASSERT(divisor != -1);
1169 __ Subu(result, zero_reg, Operand(result));
1170 }
1171 // Compute the remainder.
1172 if (divisor > 0) {
1173 __ sll(scratch, result, power);
1174 __ Subu(remainder, dividend, Operand(scratch));
1175 } else {
1176 __ sll(scratch, result, power);
1177 __ Addu(remainder, dividend, Operand(scratch));
1178 }
1179 return;
1180 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) {
1181 // Use magic numbers for a few specific divisors.
1182 // Details and proofs can be found in:
1183 // - Hacker's Delight, Henry S. Warren, Jr.
1184 // - The PowerPC Compiler Writer's Guide
1185 // and probably many others.
1186 //
1187 // We handle
1188 // <divisor with magic numbers> * <power of 2>
1189 // but not
1190 // <divisor with magic numbers> * <other divisor with magic numbers>
1191 DivMagicNumbers magic_numbers =
1192 DivMagicNumberFor(divisor_abs >> power_of_2_factor);
1193 // Branch and condition free code for integer division by a power
1194 // of two.
1195 const int32_t M = magic_numbers.M;
1196 const int32_t s = magic_numbers.s + power_of_2_factor;
1197
1198 __ li(scratch, Operand(M));
1199 __ mult(dividend, scratch);
1200 __ mfhi(scratch);
1201 if (M < 0) {
1202 __ Addu(scratch, scratch, Operand(dividend));
1203 }
1204 if (s > 0) {
1205 __ sra(scratch, scratch, s);
1206 __ mov(scratch, scratch);
1207 }
1208 __ srl(at, dividend, 31);
1209 __ Addu(result, scratch, Operand(at));
1210 if (divisor < 0) __ Subu(result, zero_reg, Operand(result));
1211 // Compute the remainder.
1212 __ li(scratch, Operand(divisor));
1213 __ Mul(scratch, result, Operand(scratch));
1214 __ Subu(remainder, dividend, Operand(scratch));
1215 } else {
1216 __ li(scratch, Operand(divisor));
1217 __ div(dividend, scratch);
1218 __ mfhi(remainder);
1219 __ mflo(result);
1220 }
1221 }
1222}
1223
1224
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001225void LCodeGen::DoDivI(LDivI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001226 const Register left = ToRegister(instr->left());
1227 const Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001228 const Register result = ToRegister(instr->result());
1229
1230 // On MIPS div is asynchronous - it will run in the background while we
1231 // check for special cases.
1232 __ div(left, right);
1233
1234 // Check for x / 0.
1235 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1236 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1237 }
1238
1239 // Check for (0 / -x) that will produce negative zero.
1240 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1241 Label left_not_zero;
1242 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1243 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1244 __ bind(&left_not_zero);
1245 }
1246
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001247 // Check for (kMinInt / -1).
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001248 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1249 Label left_not_min_int;
1250 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1251 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1252 __ bind(&left_not_min_int);
1253 }
1254
danno@chromium.org41728482013-06-12 22:31:22 +00001255 if (!instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1256 __ mfhi(result);
1257 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg));
1258 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259 __ mflo(result);
1260}
1261
1262
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001263void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
1264 DoubleRegister addend = ToDoubleRegister(instr->addend());
1265 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
1266 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
1267
1268 // This is computed in-place.
1269 ASSERT(addend.is(ToDoubleRegister(instr->result())));
1270
1271 __ madd_d(addend, addend, multiplier, multiplicand);
1272}
1273
1274
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001275void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1276 const Register result = ToRegister(instr->result());
1277 const Register left = ToRegister(instr->left());
1278 const Register remainder = ToRegister(instr->temp());
1279 const Register scratch = scratch0();
1280
1281 if (instr->right()->IsConstantOperand()) {
1282 Label done;
1283 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
1284 if (divisor < 0) {
1285 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1286 }
1287 EmitSignedIntegerDivisionByConstant(result,
1288 left,
1289 divisor,
1290 remainder,
1291 scratch,
1292 instr->environment());
1293 // We performed a truncating division. Correct the result if necessary.
1294 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1295 __ Xor(scratch , remainder, Operand(divisor));
1296 __ Branch(&done, ge, scratch, Operand(zero_reg));
1297 __ Subu(result, result, Operand(1));
1298 __ bind(&done);
1299 } else {
1300 Label done;
1301 const Register right = ToRegister(instr->right());
1302
1303 // On MIPS div is asynchronous - it will run in the background while we
1304 // check for special cases.
1305 __ div(left, right);
1306
1307 // Check for x / 0.
1308 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1309
1310 // Check for (0 / -x) that will produce negative zero.
1311 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1312 Label left_not_zero;
1313 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1314 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1315 __ bind(&left_not_zero);
1316 }
1317
1318 // Check for (kMinInt / -1).
1319 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1320 Label left_not_min_int;
1321 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1322 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1323 __ bind(&left_not_min_int);
1324 }
1325
1326 __ mfhi(remainder);
1327 __ mflo(result);
1328
1329 // We performed a truncating division. Correct the result if necessary.
1330 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1331 __ Xor(scratch , remainder, Operand(right));
1332 __ Branch(&done, ge, scratch, Operand(zero_reg));
1333 __ Subu(result, result, Operand(1));
1334 __ bind(&done);
1335 }
1336}
1337
1338
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001339void LCodeGen::DoMulI(LMulI* instr) {
1340 Register scratch = scratch0();
1341 Register result = ToRegister(instr->result());
1342 // Note that result may alias left.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001343 Register left = ToRegister(instr->left());
1344 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346 bool bailout_on_minus_zero =
1347 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001348 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001349
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001350 if (right_op->IsConstantOperand()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001351 int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001352
1353 if (bailout_on_minus_zero && (constant < 0)) {
1354 // The case of a null constant will be handled separately.
1355 // If constant is negative and left is null, the result should be -0.
1356 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1357 }
1358
1359 switch (constant) {
1360 case -1:
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001361 if (overflow) {
1362 __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
1363 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
1364 } else {
1365 __ Subu(result, zero_reg, left);
1366 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001367 break;
1368 case 0:
1369 if (bailout_on_minus_zero) {
1370 // If left is strictly negative and the constant is null, the
1371 // result is -0. Deoptimize if required, otherwise return 0.
1372 DeoptimizeIf(lt, instr->environment(), left, Operand(zero_reg));
1373 }
1374 __ mov(result, zero_reg);
1375 break;
1376 case 1:
1377 // Nothing to do.
1378 __ Move(result, left);
1379 break;
1380 default:
1381 // Multiplying by powers of two and powers of two plus or minus
1382 // one can be done faster with shifted operands.
1383 // For other constants we emit standard code.
1384 int32_t mask = constant >> 31;
1385 uint32_t constant_abs = (constant + mask) ^ mask;
1386
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001387 if (IsPowerOf2(constant_abs)) {
1388 int32_t shift = WhichPowerOf2(constant_abs);
1389 __ sll(result, left, shift);
1390 // Correct the sign of the result if the constant is negative.
1391 if (constant < 0) __ Subu(result, zero_reg, result);
1392 } else if (IsPowerOf2(constant_abs - 1)) {
1393 int32_t shift = WhichPowerOf2(constant_abs - 1);
1394 __ sll(scratch, left, shift);
1395 __ Addu(result, scratch, left);
1396 // Correct the sign of the result if the constant is negative.
1397 if (constant < 0) __ Subu(result, zero_reg, result);
1398 } else if (IsPowerOf2(constant_abs + 1)) {
1399 int32_t shift = WhichPowerOf2(constant_abs + 1);
1400 __ sll(scratch, left, shift);
1401 __ Subu(result, scratch, left);
1402 // Correct the sign of the result if the constant is negative.
1403 if (constant < 0) __ Subu(result, zero_reg, result);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001404 } else {
1405 // Generate standard code.
1406 __ li(at, constant);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001407 __ Mul(result, left, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001408 }
1409 }
1410
1411 } else {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001412 ASSERT(right_op->IsRegister());
1413 Register right = ToRegister(right_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001414
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001415 if (overflow) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001416 // hi:lo = left * right.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001417 if (instr->hydrogen()->representation().IsSmi()) {
1418 __ SmiUntag(result, left);
1419 __ mult(result, right);
1420 __ mfhi(scratch);
1421 __ mflo(result);
1422 } else {
1423 __ mult(left, right);
1424 __ mfhi(scratch);
1425 __ mflo(result);
1426 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001427 __ sra(at, result, 31);
1428 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
1429 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001430 if (instr->hydrogen()->representation().IsSmi()) {
1431 __ SmiUntag(result, left);
1432 __ Mul(result, result, right);
1433 } else {
1434 __ Mul(result, left, right);
1435 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001436 }
1437
1438 if (bailout_on_minus_zero) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001439 Label done;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001440 __ Xor(at, left, right);
1441 __ Branch(&done, ge, at, Operand(zero_reg));
1442 // Bail out if the result is minus zero.
1443 DeoptimizeIf(eq,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001444 instr->environment(),
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001445 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001446 Operand(zero_reg));
1447 __ bind(&done);
1448 }
1449 }
1450}
1451
1452
1453void LCodeGen::DoBitI(LBitI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001454 LOperand* left_op = instr->left();
1455 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001456 ASSERT(left_op->IsRegister());
1457 Register left = ToRegister(left_op);
1458 Register result = ToRegister(instr->result());
1459 Operand right(no_reg);
1460
1461 if (right_op->IsStackSlot() || right_op->IsArgument()) {
1462 right = Operand(EmitLoadRegister(right_op, at));
1463 } else {
1464 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
1465 right = ToOperand(right_op);
1466 }
1467
1468 switch (instr->op()) {
1469 case Token::BIT_AND:
1470 __ And(result, left, right);
1471 break;
1472 case Token::BIT_OR:
1473 __ Or(result, left, right);
1474 break;
1475 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001476 if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) {
1477 __ Nor(result, zero_reg, left);
1478 } else {
1479 __ Xor(result, left, right);
1480 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001481 break;
1482 default:
1483 UNREACHABLE();
1484 break;
1485 }
1486}
1487
1488
1489void LCodeGen::DoShiftI(LShiftI* instr) {
1490 // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
1491 // result may alias either of them.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001492 LOperand* right_op = instr->right();
1493 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001494 Register result = ToRegister(instr->result());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001495 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001496
1497 if (right_op->IsRegister()) {
1498 // No need to mask the right operand on MIPS, it is built into the variable
1499 // shift instructions.
1500 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001501 case Token::ROR:
1502 __ Ror(result, left, Operand(ToRegister(right_op)));
1503 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001504 case Token::SAR:
1505 __ srav(result, left, ToRegister(right_op));
1506 break;
1507 case Token::SHR:
1508 __ srlv(result, left, ToRegister(right_op));
1509 if (instr->can_deopt()) {
1510 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
1511 }
1512 break;
1513 case Token::SHL:
1514 __ sllv(result, left, ToRegister(right_op));
1515 break;
1516 default:
1517 UNREACHABLE();
1518 break;
1519 }
1520 } else {
1521 // Mask the right_op operand.
1522 int value = ToInteger32(LConstantOperand::cast(right_op));
1523 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1524 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001525 case Token::ROR:
1526 if (shift_count != 0) {
1527 __ Ror(result, left, Operand(shift_count));
1528 } else {
1529 __ Move(result, left);
1530 }
1531 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001532 case Token::SAR:
1533 if (shift_count != 0) {
1534 __ sra(result, left, shift_count);
1535 } else {
1536 __ Move(result, left);
1537 }
1538 break;
1539 case Token::SHR:
1540 if (shift_count != 0) {
1541 __ srl(result, left, shift_count);
1542 } else {
1543 if (instr->can_deopt()) {
1544 __ And(at, left, Operand(0x80000000));
1545 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
1546 }
1547 __ Move(result, left);
1548 }
1549 break;
1550 case Token::SHL:
1551 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001552 if (instr->hydrogen_value()->representation().IsSmi() &&
1553 instr->can_deopt()) {
1554 if (shift_count != 1) {
1555 __ sll(result, left, shift_count - 1);
1556 __ SmiTagCheckOverflow(result, result, scratch);
1557 } else {
1558 __ SmiTagCheckOverflow(result, left, scratch);
1559 }
1560 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
1561 } else {
1562 __ sll(result, left, shift_count);
1563 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001564 } else {
1565 __ Move(result, left);
1566 }
1567 break;
1568 default:
1569 UNREACHABLE();
1570 break;
1571 }
1572 }
1573}
1574
1575
1576void LCodeGen::DoSubI(LSubI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001577 LOperand* left = instr->left();
1578 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001579 LOperand* result = instr->result();
1580 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1581
1582 if (!can_overflow) {
1583 if (right->IsStackSlot() || right->IsArgument()) {
1584 Register right_reg = EmitLoadRegister(right, at);
1585 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg));
1586 } else {
1587 ASSERT(right->IsRegister() || right->IsConstantOperand());
1588 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
1589 }
1590 } else { // can_overflow.
1591 Register overflow = scratch0();
1592 Register scratch = scratch1();
1593 if (right->IsStackSlot() ||
1594 right->IsArgument() ||
1595 right->IsConstantOperand()) {
1596 Register right_reg = EmitLoadRegister(right, scratch);
1597 __ SubuAndCheckForOverflow(ToRegister(result),
1598 ToRegister(left),
1599 right_reg,
1600 overflow); // Reg at also used as scratch.
1601 } else {
1602 ASSERT(right->IsRegister());
1603 // Due to overflow check macros not supporting constant operands,
1604 // handling the IsConstantOperand case was moved to prev if clause.
1605 __ SubuAndCheckForOverflow(ToRegister(result),
1606 ToRegister(left),
1607 ToRegister(right),
1608 overflow); // Reg at also used as scratch.
1609 }
1610 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1611 }
1612}
1613
1614
1615void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001616 __ li(ToRegister(instr->result()), Operand(instr->value()));
1617}
1618
1619
1620void LCodeGen::DoConstantS(LConstantS* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001621 __ li(ToRegister(instr->result()), Operand(instr->value()));
1622}
1623
1624
1625void LCodeGen::DoConstantD(LConstantD* instr) {
1626 ASSERT(instr->result()->IsDoubleRegister());
1627 DoubleRegister result = ToDoubleRegister(instr->result());
1628 double v = instr->value();
1629 __ Move(result, v);
1630}
1631
1632
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001633void LCodeGen::DoConstantE(LConstantE* instr) {
1634 __ li(ToRegister(instr->result()), Operand(instr->value()));
1635}
1636
1637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001638void LCodeGen::DoConstantT(LConstantT* instr) {
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +00001639 Handle<Object> value = instr->value(isolate());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001640 AllowDeferredHandleDereference smi_check;
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001641 __ li(ToRegister(instr->result()), value);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001642}
1643
1644
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001645void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1646 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001647 Register map = ToRegister(instr->value());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001648 __ EnumLength(result, map);
1649}
1650
1651
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001652void LCodeGen::DoDateField(LDateField* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001653 Register object = ToRegister(instr->date());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001654 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001655 Register scratch = ToRegister(instr->temp());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001656 Smi* index = instr->index();
1657 Label runtime, done;
1658 ASSERT(object.is(a0));
1659 ASSERT(result.is(v0));
1660 ASSERT(!scratch.is(scratch0()));
1661 ASSERT(!scratch.is(object));
1662
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001663 __ SmiTst(object, at);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001664 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001665 __ GetObjectType(object, scratch, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001666 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001667
1668 if (index->value() == 0) {
1669 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
1670 } else {
1671 if (index->value() < JSDate::kFirstUncachedField) {
1672 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1673 __ li(scratch, Operand(stamp));
1674 __ lw(scratch, MemOperand(scratch));
1675 __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
1676 __ Branch(&runtime, ne, scratch, Operand(scratch0()));
1677 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
1678 kPointerSize * index->value()));
1679 __ jmp(&done);
1680 }
1681 __ bind(&runtime);
1682 __ PrepareCallCFunction(2, scratch);
1683 __ li(a1, Operand(index));
1684 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1685 __ bind(&done);
1686 }
1687}
1688
1689
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001690MemOperand LCodeGen::BuildSeqStringOperand(Register string,
1691 LOperand* index,
1692 String::Encoding encoding) {
1693 if (index->IsConstantOperand()) {
1694 int offset = ToInteger32(LConstantOperand::cast(index));
1695 if (encoding == String::TWO_BYTE_ENCODING) {
1696 offset *= kUC16Size;
1697 }
1698 STATIC_ASSERT(kCharSize == 1);
1699 return FieldMemOperand(string, SeqString::kHeaderSize + offset);
1700 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001701 Register scratch = scratch0();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001702 ASSERT(!scratch.is(string));
1703 ASSERT(!scratch.is(ToRegister(index)));
1704 if (encoding == String::ONE_BYTE_ENCODING) {
1705 __ Addu(scratch, string, ToRegister(index));
1706 } else {
1707 STATIC_ASSERT(kUC16Size == 2);
1708 __ sll(scratch, ToRegister(index), 1);
1709 __ Addu(scratch, string, scratch);
1710 }
1711 return FieldMemOperand(scratch, SeqString::kHeaderSize);
1712}
1713
1714
1715void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1716 String::Encoding encoding = instr->hydrogen()->encoding();
1717 Register string = ToRegister(instr->string());
1718 Register result = ToRegister(instr->result());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001719
1720 if (FLAG_debug_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001721 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001722 __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
1723 __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001724
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001725 __ And(scratch, scratch,
1726 Operand(kStringRepresentationMask | kStringEncodingMask));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001727 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1728 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001729 __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001730 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00001731 __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001732 }
1733
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001734 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1735 if (encoding == String::ONE_BYTE_ENCODING) {
1736 __ lbu(result, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001737 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001738 __ lhu(result, operand);
1739 }
1740}
1741
1742
1743void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1744 String::Encoding encoding = instr->hydrogen()->encoding();
1745 Register string = ToRegister(instr->string());
1746 Register value = ToRegister(instr->value());
1747
1748 if (FLAG_debug_code) {
1749 Register scratch = scratch0();
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001750 Register index = ToRegister(instr->index());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001751 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1752 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001753 int encoding_mask =
1754 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1755 ? one_byte_seq_type : two_byte_seq_type;
1756 __ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001757 }
1758
1759 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1760 if (encoding == String::ONE_BYTE_ENCODING) {
1761 __ sb(value, operand);
1762 } else {
1763 __ sh(value, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001764 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001765}
1766
1767
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001768void LCodeGen::DoAddI(LAddI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001769 LOperand* left = instr->left();
1770 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001771 LOperand* result = instr->result();
1772 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1773
1774 if (!can_overflow) {
1775 if (right->IsStackSlot() || right->IsArgument()) {
1776 Register right_reg = EmitLoadRegister(right, at);
1777 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg));
1778 } else {
1779 ASSERT(right->IsRegister() || right->IsConstantOperand());
1780 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
1781 }
1782 } else { // can_overflow.
1783 Register overflow = scratch0();
1784 Register scratch = scratch1();
1785 if (right->IsStackSlot() ||
1786 right->IsArgument() ||
1787 right->IsConstantOperand()) {
1788 Register right_reg = EmitLoadRegister(right, scratch);
1789 __ AdduAndCheckForOverflow(ToRegister(result),
1790 ToRegister(left),
1791 right_reg,
1792 overflow); // Reg at also used as scratch.
1793 } else {
1794 ASSERT(right->IsRegister());
1795 // Due to overflow check macros not supporting constant operands,
1796 // handling the IsConstantOperand case was moved to prev if clause.
1797 __ AdduAndCheckForOverflow(ToRegister(result),
1798 ToRegister(left),
1799 ToRegister(right),
1800 overflow); // Reg at also used as scratch.
1801 }
1802 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1803 }
1804}
1805
1806
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001807void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001808 LOperand* left = instr->left();
1809 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001810 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1811 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001812 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001813 Register left_reg = ToRegister(left);
1814 Operand right_op = (right->IsRegister() || right->IsConstantOperand())
1815 ? ToOperand(right)
1816 : Operand(EmitLoadRegister(right, at));
1817 Register result_reg = ToRegister(instr->result());
1818 Label return_right, done;
1819 if (!result_reg.is(left_reg)) {
1820 __ Branch(&return_right, NegateCondition(condition), left_reg, right_op);
1821 __ mov(result_reg, left_reg);
1822 __ Branch(&done);
1823 }
1824 __ Branch(&done, condition, left_reg, right_op);
1825 __ bind(&return_right);
1826 __ Addu(result_reg, zero_reg, right_op);
1827 __ bind(&done);
1828 } else {
1829 ASSERT(instr->hydrogen()->representation().IsDouble());
1830 FPURegister left_reg = ToDoubleRegister(left);
1831 FPURegister right_reg = ToDoubleRegister(right);
1832 FPURegister result_reg = ToDoubleRegister(instr->result());
1833 Label check_nan_left, check_zero, return_left, return_right, done;
1834 __ BranchF(&check_zero, &check_nan_left, eq, left_reg, right_reg);
1835 __ BranchF(&return_left, NULL, condition, left_reg, right_reg);
1836 __ Branch(&return_right);
1837
1838 __ bind(&check_zero);
1839 // left == right != 0.
1840 __ BranchF(&return_left, NULL, ne, left_reg, kDoubleRegZero);
1841 // At this point, both left and right are either 0 or -0.
1842 if (operation == HMathMinMax::kMathMin) {
1843 __ neg_d(left_reg, left_reg);
1844 __ sub_d(result_reg, left_reg, right_reg);
1845 __ neg_d(result_reg, result_reg);
1846 } else {
1847 __ add_d(result_reg, left_reg, right_reg);
1848 }
1849 __ Branch(&done);
1850
1851 __ bind(&check_nan_left);
1852 // left == NaN.
1853 __ BranchF(NULL, &return_left, eq, left_reg, left_reg);
1854 __ bind(&return_right);
1855 if (!right_reg.is(result_reg)) {
1856 __ mov_d(result_reg, right_reg);
1857 }
1858 __ Branch(&done);
1859
1860 __ bind(&return_left);
1861 if (!left_reg.is(result_reg)) {
1862 __ mov_d(result_reg, left_reg);
1863 }
1864 __ bind(&done);
1865 }
1866}
1867
1868
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001869void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001870 DoubleRegister left = ToDoubleRegister(instr->left());
1871 DoubleRegister right = ToDoubleRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001872 DoubleRegister result = ToDoubleRegister(instr->result());
1873 switch (instr->op()) {
1874 case Token::ADD:
1875 __ add_d(result, left, right);
1876 break;
1877 case Token::SUB:
1878 __ sub_d(result, left, right);
1879 break;
1880 case Token::MUL:
1881 __ mul_d(result, left, right);
1882 break;
1883 case Token::DIV:
1884 __ div_d(result, left, right);
1885 break;
1886 case Token::MOD: {
1887 // Save a0-a3 on the stack.
1888 RegList saved_regs = a0.bit() | a1.bit() | a2.bit() | a3.bit();
1889 __ MultiPush(saved_regs);
1890
1891 __ PrepareCallCFunction(0, 2, scratch0());
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001892 __ MovToFloatParameters(left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001893 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001894 ExternalReference::mod_two_doubles_operation(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001895 0, 2);
1896 // Move the result in the double result register.
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001897 __ MovFromFloatResult(result);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001898
1899 // Restore saved register.
1900 __ MultiPop(saved_regs);
1901 break;
1902 }
1903 default:
1904 UNREACHABLE();
1905 break;
1906 }
1907}
1908
1909
1910void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001911 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001912 ASSERT(ToRegister(instr->left()).is(a1));
1913 ASSERT(ToRegister(instr->right()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001914 ASSERT(ToRegister(instr->result()).is(v0));
1915
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001916 BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001917 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001918 // Other arch use a nop here, to signal that there is no inlined
1919 // patchable code. Mips does not need the nop, since our marker
1920 // instruction (andi zero_reg) will never be used in normal code.
1921}
1922
1923
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001924template<class InstrType>
1925void LCodeGen::EmitBranch(InstrType instr,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001926 Condition condition,
1927 Register src1,
1928 const Operand& src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001929 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001930 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001931
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001932 int next_block = GetNextEmittedBlock();
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001933 if (right_block == left_block || condition == al) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001934 EmitGoto(left_block);
1935 } else if (left_block == next_block) {
1936 __ Branch(chunk_->GetAssemblyLabel(right_block),
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001937 NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001938 } else if (right_block == next_block) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001939 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001940 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001941 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001942 __ Branch(chunk_->GetAssemblyLabel(right_block));
1943 }
1944}
1945
1946
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001947template<class InstrType>
1948void LCodeGen::EmitBranchF(InstrType instr,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001949 Condition condition,
1950 FPURegister src1,
1951 FPURegister src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001952 int right_block = instr->FalseDestination(chunk_);
1953 int left_block = instr->TrueDestination(chunk_);
1954
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001955 int next_block = GetNextEmittedBlock();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001956 if (right_block == left_block) {
1957 EmitGoto(left_block);
1958 } else if (left_block == next_block) {
1959 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001960 NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001961 } else if (right_block == next_block) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001962 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL,
1963 condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001964 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001965 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL,
1966 condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 __ Branch(chunk_->GetAssemblyLabel(right_block));
1968 }
1969}
1970
1971
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001972template<class InstrType>
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00001973void LCodeGen::EmitFalseBranch(InstrType instr,
1974 Condition condition,
1975 Register src1,
1976 const Operand& src2) {
1977 int false_block = instr->FalseDestination(chunk_);
1978 __ Branch(chunk_->GetAssemblyLabel(false_block), condition, src1, src2);
1979}
1980
1981
1982template<class InstrType>
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001983void LCodeGen::EmitFalseBranchF(InstrType instr,
1984 Condition condition,
1985 FPURegister src1,
1986 FPURegister src2) {
1987 int false_block = instr->FalseDestination(chunk_);
1988 __ BranchF(chunk_->GetAssemblyLabel(false_block), NULL,
1989 condition, src1, src2);
1990}
1991
1992
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001993void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1994 __ stop("LDebugBreak");
1995}
1996
1997
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001998void LCodeGen::DoBranch(LBranch* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001999 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002000 if (r.IsInteger32() || r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002001 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002002 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002003 EmitBranch(instr, ne, reg, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002004 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002005 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002006 DoubleRegister reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002007 // Test the double value. Zero and NaN are false.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002008 EmitBranchF(instr, nue, reg, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 } else {
2010 ASSERT(r.IsTagged());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002011 Register reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 HType type = instr->hydrogen()->value()->type();
2013 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002014 ASSERT(!info()->IsStub());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002015 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002016 EmitBranch(instr, eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002018 ASSERT(!info()->IsStub());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002019 EmitBranch(instr, ne, reg, Operand(zero_reg));
2020 } else if (type.IsJSArray()) {
2021 ASSERT(!info()->IsStub());
2022 EmitBranch(instr, al, zero_reg, Operand(zero_reg));
2023 } else if (type.IsHeapNumber()) {
2024 ASSERT(!info()->IsStub());
2025 DoubleRegister dbl_scratch = double_scratch0();
2026 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
2027 // Test the double value. Zero and NaN are false.
2028 EmitBranchF(instr, nue, dbl_scratch, kDoubleRegZero);
2029 } else if (type.IsString()) {
2030 ASSERT(!info()->IsStub());
2031 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
2032 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002033 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002034 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2035 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002036 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002037
2038 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2039 // undefined -> false.
2040 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002041 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002042 }
2043 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2044 // Boolean -> its value.
2045 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002046 __ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 __ LoadRoot(at, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002048 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002049 }
2050 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2051 // 'null' -> false.
2052 __ LoadRoot(at, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002053 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002054 }
2055
2056 if (expected.Contains(ToBooleanStub::SMI)) {
2057 // Smis: 0 -> false, all other -> true.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002058 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg));
2059 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 } else if (expected.NeedsMap()) {
2061 // If we need a map later and have a Smi -> deopt.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002062 __ SmiTst(reg, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002063 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
2064 }
2065
2066 const Register map = scratch0();
2067 if (expected.NeedsMap()) {
2068 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset));
2069 if (expected.CanBeUndetectable()) {
2070 // Undetectable -> false.
2071 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
2072 __ And(at, at, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002073 __ Branch(instr->FalseLabel(chunk_), ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002074 }
2075 }
2076
2077 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2078 // spec object -> true.
2079 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002080 __ Branch(instr->TrueLabel(chunk_),
2081 ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002082 }
2083
2084 if (expected.Contains(ToBooleanStub::STRING)) {
2085 // String value -> false iff empty.
2086 Label not_string;
2087 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
2088 __ Branch(&not_string, ge , at, Operand(FIRST_NONSTRING_TYPE));
2089 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002090 __ Branch(instr->TrueLabel(chunk_), ne, at, Operand(zero_reg));
2091 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002092 __ bind(&not_string);
2093 }
2094
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002095 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2096 // Symbol value -> true.
2097 const Register scratch = scratch1();
2098 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002099 __ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002100 }
2101
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002102 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2103 // heap number -> false iff +0, -0, or NaN.
2104 DoubleRegister dbl_scratch = double_scratch0();
2105 Label not_heap_number;
2106 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
2107 __ Branch(&not_heap_number, ne, map, Operand(at));
2108 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002109 __ BranchF(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2110 ne, dbl_scratch, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002111 // Falls through if dbl_scratch == 0.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002112 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 __ bind(&not_heap_number);
2114 }
2115
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002116 if (!expected.IsGeneric()) {
2117 // We've seen something for the first time -> deopt.
2118 // This can only happen if we are not generic already.
2119 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
2120 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002121 }
2122 }
2123}
2124
2125
2126void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002127 if (!IsNextEmittedBlock(block)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002128 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002129 }
2130}
2131
2132
2133void LCodeGen::DoGoto(LGoto* instr) {
2134 EmitGoto(instr->block_id());
2135}
2136
2137
2138Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2139 Condition cond = kNoCondition;
2140 switch (op) {
2141 case Token::EQ:
2142 case Token::EQ_STRICT:
2143 cond = eq;
2144 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002145 case Token::NE:
2146 case Token::NE_STRICT:
2147 cond = ne;
2148 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002149 case Token::LT:
2150 cond = is_unsigned ? lo : lt;
2151 break;
2152 case Token::GT:
2153 cond = is_unsigned ? hi : gt;
2154 break;
2155 case Token::LTE:
2156 cond = is_unsigned ? ls : le;
2157 break;
2158 case Token::GTE:
2159 cond = is_unsigned ? hs : ge;
2160 break;
2161 case Token::IN:
2162 case Token::INSTANCEOF:
2163 default:
2164 UNREACHABLE();
2165 }
2166 return cond;
2167}
2168
2169
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002170void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002171 LOperand* left = instr->left();
2172 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002173 Condition cond = TokenToCondition(instr->op(), false);
2174
2175 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2176 // We can statically evaluate the comparison.
2177 double left_val = ToDouble(LConstantOperand::cast(left));
2178 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002179 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2180 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002181 EmitGoto(next_block);
2182 } else {
2183 if (instr->is_double()) {
2184 // Compare left and right as doubles and load the
2185 // resulting flags into the normal status register.
2186 FPURegister left_reg = ToDoubleRegister(left);
2187 FPURegister right_reg = ToDoubleRegister(right);
2188
2189 // If a NaN is involved, i.e. the result is unordered,
2190 // jump to false block label.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002191 __ BranchF(NULL, instr->FalseLabel(chunk_), eq,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002192 left_reg, right_reg);
2193
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002194 EmitBranchF(instr, cond, left_reg, right_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002195 } else {
2196 Register cmp_left;
2197 Operand cmp_right = Operand(0);
2198
2199 if (right->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002200 int32_t value = ToInteger32(LConstantOperand::cast(right));
2201 if (instr->hydrogen_value()->representation().IsSmi()) {
2202 cmp_left = ToRegister(left);
2203 cmp_right = Operand(Smi::FromInt(value));
2204 } else {
2205 cmp_left = ToRegister(left);
2206 cmp_right = Operand(value);
2207 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002208 } else if (left->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002209 int32_t value = ToInteger32(LConstantOperand::cast(left));
2210 if (instr->hydrogen_value()->representation().IsSmi()) {
2211 cmp_left = ToRegister(right);
2212 cmp_right = Operand(Smi::FromInt(value));
2213 } else {
2214 cmp_left = ToRegister(right);
2215 cmp_right = Operand(value);
2216 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217 // We transposed the operands. Reverse the condition.
2218 cond = ReverseCondition(cond);
2219 } else {
2220 cmp_left = ToRegister(left);
2221 cmp_right = Operand(ToRegister(right));
2222 }
2223
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002224 EmitBranch(instr, cond, cmp_left, cmp_right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002225 }
2226 }
2227}
2228
2229
2230void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002231 Register left = ToRegister(instr->left());
2232 Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002233
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002234 EmitBranch(instr, eq, left, Operand(right));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002235}
2236
2237
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002238void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2239 if (instr->hydrogen()->representation().IsTagged()) {
2240 Register input_reg = ToRegister(instr->object());
2241 __ li(at, Operand(factory()->the_hole_value()));
2242 EmitBranch(instr, eq, input_reg, Operand(at));
2243 return;
2244 }
2245
2246 DoubleRegister input_reg = ToDoubleRegister(instr->object());
2247 EmitFalseBranchF(instr, eq, input_reg, input_reg);
2248
2249 Register scratch = scratch0();
2250 __ FmoveHigh(scratch, input_reg);
2251 EmitBranch(instr, eq, scratch, Operand(kHoleNanUpper32));
2252}
2253
2254
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002255void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2256 Representation rep = instr->hydrogen()->value()->representation();
2257 ASSERT(!rep.IsInteger32());
2258 Register scratch = ToRegister(instr->temp());
2259
2260 if (rep.IsDouble()) {
2261 DoubleRegister value = ToDoubleRegister(instr->value());
2262 EmitFalseBranchF(instr, ne, value, kDoubleRegZero);
2263 __ FmoveHigh(scratch, value);
2264 __ li(at, 0x80000000);
2265 } else {
2266 Register value = ToRegister(instr->value());
2267 __ CheckMap(value,
2268 scratch,
2269 Heap::kHeapNumberMapRootIndex,
2270 instr->FalseLabel(chunk()),
2271 DO_SMI_CHECK);
2272 __ lw(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
2273 EmitFalseBranch(instr, ne, scratch, Operand(0x80000000));
2274 __ lw(scratch, FieldMemOperand(value, HeapNumber::kMantissaOffset));
2275 __ mov(at, zero_reg);
2276 }
2277 EmitBranch(instr, eq, scratch, Operand(at));
2278}
2279
2280
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002281Condition LCodeGen::EmitIsObject(Register input,
2282 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +00002283 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002284 Label* is_not_object,
2285 Label* is_object) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002286 __ JumpIfSmi(input, is_not_object);
2287
2288 __ LoadRoot(temp2, Heap::kNullValueRootIndex);
2289 __ Branch(is_object, eq, input, Operand(temp2));
2290
2291 // Load map.
2292 __ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
2293 // Undetectable objects behave like undefined.
2294 __ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
2295 __ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
2296 __ Branch(is_not_object, ne, temp2, Operand(zero_reg));
2297
2298 // Load instance type and check that it is in object type range.
2299 __ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
2300 __ Branch(is_not_object,
2301 lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2302
2303 return le;
2304}
2305
2306
2307void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002308 Register reg = ToRegister(instr->value());
2309 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002310 Register temp2 = scratch0();
2311
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002312 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002313 EmitIsObject(reg, temp1, temp2,
2314 instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002315
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002316 EmitBranch(instr, true_cond, temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002317 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2318}
2319
2320
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002321Condition LCodeGen::EmitIsString(Register input,
2322 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002323 Label* is_not_string,
2324 SmiCheck check_needed = INLINE_SMI_CHECK) {
2325 if (check_needed == INLINE_SMI_CHECK) {
2326 __ JumpIfSmi(input, is_not_string);
2327 }
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002328 __ GetObjectType(input, temp1, temp1);
2329
2330 return lt;
2331}
2332
2333
2334void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002335 Register reg = ToRegister(instr->value());
2336 Register temp1 = ToRegister(instr->temp());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002337
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002338 SmiCheck check_needed =
2339 instr->hydrogen()->value()->IsHeapObject()
2340 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002341 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002342 EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002343
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002344 EmitBranch(instr, true_cond, temp1,
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002345 Operand(FIRST_NONSTRING_TYPE));
2346}
2347
2348
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002349void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002350 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 __ And(at, input_reg, kSmiTagMask);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002352 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002353}
2354
2355
2356void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002357 Register input = ToRegister(instr->value());
2358 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002359
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002360 if (!instr->hydrogen()->value()->IsHeapObject()) {
2361 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2362 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002363 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset));
2364 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
2365 __ And(at, temp, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002366 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002367}
2368
2369
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002370static Condition ComputeCompareCondition(Token::Value op) {
2371 switch (op) {
2372 case Token::EQ_STRICT:
2373 case Token::EQ:
2374 return eq;
2375 case Token::LT:
2376 return lt;
2377 case Token::GT:
2378 return gt;
2379 case Token::LTE:
2380 return le;
2381 case Token::GTE:
2382 return ge;
2383 default:
2384 UNREACHABLE();
2385 return kNoCondition;
2386 }
2387}
2388
2389
2390void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002391 ASSERT(ToRegister(instr->context()).is(cp));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002392 Token::Value op = instr->op();
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002393
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002394 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002395 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2396
2397 Condition condition = ComputeCompareCondition(op);
2398
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002399 EmitBranch(instr, condition, v0, Operand(zero_reg));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002400}
2401
2402
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002403static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2404 InstanceType from = instr->from();
2405 InstanceType to = instr->to();
2406 if (from == FIRST_TYPE) return to;
2407 ASSERT(from == to || to == LAST_TYPE);
2408 return from;
2409}
2410
2411
2412static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2413 InstanceType from = instr->from();
2414 InstanceType to = instr->to();
2415 if (from == to) return eq;
2416 if (to == LAST_TYPE) return hs;
2417 if (from == FIRST_TYPE) return ls;
2418 UNREACHABLE();
2419 return eq;
2420}
2421
2422
2423void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2424 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002425 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002426
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002427 if (!instr->hydrogen()->value()->IsHeapObject()) {
2428 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2429 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002430
2431 __ GetObjectType(input, scratch, scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002432 EmitBranch(instr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002433 BranchCondition(instr->hydrogen()),
2434 scratch,
2435 Operand(TestType(instr->hydrogen())));
2436}
2437
2438
2439void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002440 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002441 Register result = ToRegister(instr->result());
2442
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002443 __ AssertString(input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444
2445 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset));
2446 __ IndexFromHash(result, result);
2447}
2448
2449
2450void LCodeGen::DoHasCachedArrayIndexAndBranch(
2451 LHasCachedArrayIndexAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002452 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002453 Register scratch = scratch0();
2454
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002455 __ lw(scratch,
2456 FieldMemOperand(input, String::kHashFieldOffset));
2457 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002458 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002459}
2460
2461
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002462// Branches to a label or falls through with the answer in flags. Trashes
2463// the temp registers, but not the input.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002464void LCodeGen::EmitClassOfTest(Label* is_true,
2465 Label* is_false,
2466 Handle<String>class_name,
2467 Register input,
2468 Register temp,
2469 Register temp2) {
2470 ASSERT(!input.is(temp));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002471 ASSERT(!input.is(temp2));
2472 ASSERT(!temp.is(temp2));
2473
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002474 __ JumpIfSmi(input, is_false);
2475
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002476 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002477 // Assuming the following assertions, we can use the same compares to test
2478 // for both being a function type and being in the object type range.
2479 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2480 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2481 FIRST_SPEC_OBJECT_TYPE + 1);
2482 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2483 LAST_SPEC_OBJECT_TYPE - 1);
2484 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2485
2486 __ GetObjectType(input, temp, temp2);
2487 __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2488 __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2489 __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
2490 } else {
2491 // Faster code path to avoid two compares: subtract lower bound from the
2492 // actual type and do a signed compare with the width of the type range.
2493 __ GetObjectType(input, temp, temp2);
2494 __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2495 __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2496 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2497 }
2498
2499 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2500 // Check if the constructor in the map is a function.
2501 __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset));
2502
2503 // Objects with a non-function constructor have class 'Object'.
2504 __ GetObjectType(temp, temp2, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002505 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002506 __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
2507 } else {
2508 __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
2509 }
2510
2511 // temp now contains the constructor function. Grab the
2512 // instance class name from there.
2513 __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2514 __ lw(temp, FieldMemOperand(temp,
2515 SharedFunctionInfo::kInstanceClassNameOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002516 // The class name we are testing against is internalized since it's a literal.
2517 // The name in the constructor is internalized because of the way the context
2518 // is booted. This routine isn't expected to work for random API-created
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519 // classes and it doesn't have to because you can't access it with natives
ulan@chromium.org750145a2013-03-07 15:14:13 +00002520 // syntax. Since both sides are internalized it is sufficient to use an
2521 // identity comparison.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002522
2523 // End with the address of this class_name instance in temp register.
2524 // On MIPS, the caller must do the comparison with Handle<String>class_name.
2525}
2526
2527
2528void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002529 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 Register temp = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002531 Register temp2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002532 Handle<String> class_name = instr->hydrogen()->class_name();
2533
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002534 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2535 class_name, input, temp, temp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002536
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002537 EmitBranch(instr, eq, temp, Operand(class_name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002538}
2539
2540
2541void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002542 Register reg = ToRegister(instr->value());
2543 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002544
2545 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002546 EmitBranch(instr, eq, temp, Operand(instr->map()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002547}
2548
2549
2550void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002551 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002552 Label true_label, done;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002553 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0.
2554 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002555 Register result = ToRegister(instr->result());
2556 ASSERT(result.is(v0));
2557
2558 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002559 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002560
2561 __ Branch(&true_label, eq, result, Operand(zero_reg));
2562 __ li(result, Operand(factory()->false_value()));
2563 __ Branch(&done);
2564 __ bind(&true_label);
2565 __ li(result, Operand(factory()->true_value()));
2566 __ bind(&done);
2567}
2568
2569
2570void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002571 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002572 public:
2573 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2574 LInstanceOfKnownGlobal* instr)
2575 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002576 virtual void Generate() V8_OVERRIDE {
erikcorry0ad885c2011-11-21 13:51:57 +00002577 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002578 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002579 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002580 Label* map_check() { return &map_check_; }
2581
2582 private:
2583 LInstanceOfKnownGlobal* instr_;
2584 Label map_check_;
2585 };
2586
2587 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002588 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002589
2590 Label done, false_result;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002591 Register object = ToRegister(instr->value());
2592 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002593 Register result = ToRegister(instr->result());
2594
2595 ASSERT(object.is(a0));
2596 ASSERT(result.is(v0));
2597
2598 // A Smi is not instance of anything.
2599 __ JumpIfSmi(object, &false_result);
2600
2601 // This is the inlined call site instanceof cache. The two occurences of the
2602 // hole value will be patched to the last map/result pair generated by the
2603 // instanceof stub.
2604 Label cache_miss;
2605 Register map = temp;
2606 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset));
2607
2608 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
2609 __ bind(deferred->map_check()); // Label for calculating code patching.
2610 // We use Factory::the_hole_value() on purpose instead of loading from the
2611 // root array to force relocation to be able to later patch with
2612 // the cached map.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002613 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002614 __ li(at, Operand(Handle<Object>(cell)));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002615 __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002616 __ Branch(&cache_miss, ne, map, Operand(at));
2617 // We use Factory::the_hole_value() on purpose instead of loading from the
2618 // root array to force relocation to be able to later patch
2619 // with true or false.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002620 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002621 __ Branch(&done);
2622
2623 // The inlined call site cache did not match. Check null and string before
2624 // calling the deferred code.
2625 __ bind(&cache_miss);
2626 // Null is not instance of anything.
2627 __ LoadRoot(temp, Heap::kNullValueRootIndex);
2628 __ Branch(&false_result, eq, object, Operand(temp));
2629
2630 // String values is not instance of anything.
2631 Condition cc = __ IsObjectStringType(object, temp, temp);
2632 __ Branch(&false_result, cc, temp, Operand(zero_reg));
2633
2634 // Go to the deferred code.
2635 __ Branch(deferred->entry());
2636
2637 __ bind(&false_result);
2638 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2639
2640 // Here result has either true or false. Deferred code also produces true or
2641 // false object.
2642 __ bind(deferred->exit());
2643 __ bind(&done);
2644}
2645
2646
erikcorry0ad885c2011-11-21 13:51:57 +00002647void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2648 Label* map_check) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002649 Register result = ToRegister(instr->result());
2650 ASSERT(result.is(v0));
2651
2652 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2653 flags = static_cast<InstanceofStub::Flags>(
2654 flags | InstanceofStub::kArgsInRegisters);
2655 flags = static_cast<InstanceofStub::Flags>(
2656 flags | InstanceofStub::kCallSiteInlineCheck);
2657 flags = static_cast<InstanceofStub::Flags>(
2658 flags | InstanceofStub::kReturnTrueFalseObject);
2659 InstanceofStub stub(flags);
2660
2661 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002662 LoadContextFromDeferred(instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002663
2664 // Get the temp register reserved by the instruction. This needs to be t0 as
2665 // its slot of the pushing of safepoint registers is used to communicate the
2666 // offset to the location of the map check.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002667 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002668 ASSERT(temp.is(t0));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002669 __ li(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002670 static const int kAdditionalDelta = 7;
2671 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2672 Label before_push_delta;
2673 __ bind(&before_push_delta);
2674 {
2675 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002676 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002677 __ StoreToSafepointRegisterSlot(temp, temp);
2678 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002679 CallCodeGeneric(stub.GetCode(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002680 RelocInfo::CODE_TARGET,
2681 instr,
2682 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00002683 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
erikcorry0ad885c2011-11-21 13:51:57 +00002684 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002685 // Put the result value into the result register slot and
2686 // restore all registers.
2687 __ StoreToSafepointRegisterSlot(result, result);
2688}
2689
2690
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002691void LCodeGen::DoCmpT(LCmpT* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002692 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002693 Token::Value op = instr->op();
2694
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002695 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002696 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2697 // On MIPS there is no need for a "no inlined smi code" marker (nop).
2698
2699 Condition condition = ComputeCompareCondition(op);
2700 // A minor optimization that relies on LoadRoot always emitting one
2701 // instruction.
2702 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002703 Label done, check;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002704 __ Branch(USE_DELAY_SLOT, &done, condition, v0, Operand(zero_reg));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002705 __ bind(&check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002706 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002707 ASSERT_EQ(1, masm()->InstructionsGeneratedSince(&check));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002708 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002709 __ bind(&done);
2710}
2711
2712
2713void LCodeGen::DoReturn(LReturn* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002714 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002715 // Push the return value on the stack as the parameter.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002716 // Runtime::TraceExit returns its parameter in v0. We're leaving the code
2717 // managed by the register allocator and tearing down the frame, it's
2718 // safe to write to the context register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002719 __ push(v0);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002720 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002721 __ CallRuntime(Runtime::kTraceExit, 1);
2722 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002723 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002724 RestoreCallerDoubles();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002725 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002726 int no_frame_start = -1;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002727 if (NeedsEagerFrame()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002728 __ mov(sp, fp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002729 no_frame_start = masm_->pc_offset();
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002730 __ Pop(ra, fp);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002731 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002732 if (instr->has_constant_parameter_count()) {
2733 int parameter_count = ToInteger32(instr->constant_parameter_count());
2734 int32_t sp_delta = (parameter_count + 1) * kPointerSize;
2735 if (sp_delta != 0) {
2736 __ Addu(sp, sp, Operand(sp_delta));
2737 }
2738 } else {
2739 Register reg = ToRegister(instr->parameter_count());
2740 // The argument count parameter is a smi
2741 __ SmiUntag(reg);
2742 __ sll(at, reg, kPointerSizeLog2);
2743 __ Addu(sp, sp, at);
2744 }
2745
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002746 __ Jump(ra);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002747
2748 if (no_frame_start != -1) {
2749 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2750 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002751}
2752
2753
2754void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2755 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002756 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002757 __ lw(result, FieldMemOperand(at, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002758 if (instr->hydrogen()->RequiresHoleCheck()) {
2759 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2760 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2761 }
2762}
2763
2764
2765void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002766 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002767 ASSERT(ToRegister(instr->global_object()).is(a0));
2768 ASSERT(ToRegister(instr->result()).is(v0));
2769
2770 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002771 ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
2772 Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode);
2773 CallCode(ic, RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002774}
2775
2776
2777void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002778 Register value = ToRegister(instr->value());
2779 Register cell = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002780
2781 // Load the cell.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002782 __ li(cell, Operand(instr->hydrogen()->cell().handle()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002783
2784 // If the cell we are storing to contains the hole it could have
2785 // been deleted from the property dictionary. In that case, we need
2786 // to update the property details in the property dictionary to mark
2787 // it as no longer deleted.
2788 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002789 // We use a temp to check the payload.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002790 Register payload = ToRegister(instr->temp());
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002791 __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002792 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002793 DeoptimizeIf(eq, instr->environment(), payload, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002794 }
2795
2796 // Store the value.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002797 __ sw(value, FieldMemOperand(cell, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002798 // Cells are always rescanned, so no write barrier here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002799}
2800
2801
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002802
2803void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2804 Register context = ToRegister(instr->context());
2805 Register result = ToRegister(instr->result());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002806
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002807 __ lw(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002808 if (instr->hydrogen()->RequiresHoleCheck()) {
2809 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002810
2811 if (instr->hydrogen()->DeoptimizesOnHole()) {
2812 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2813 } else {
2814 Label is_not_hole;
2815 __ Branch(&is_not_hole, ne, result, Operand(at));
2816 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2817 __ bind(&is_not_hole);
2818 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002819 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002820}
2821
2822
2823void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2824 Register context = ToRegister(instr->context());
2825 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002826 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827 MemOperand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002828
2829 Label skip_assignment;
2830
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002831 if (instr->hydrogen()->RequiresHoleCheck()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002832 __ lw(scratch, target);
2833 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002834
2835 if (instr->hydrogen()->DeoptimizesOnHole()) {
2836 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
2837 } else {
2838 __ Branch(&skip_assignment, ne, scratch, Operand(at));
2839 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002840 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002842 __ sw(value, target);
2843 if (instr->hydrogen()->NeedsWriteBarrier()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002844 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002845 instr->hydrogen()->value()->IsHeapObject()
2846 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002847 __ RecordWriteContextSlot(context,
2848 target.offset(),
2849 value,
2850 scratch0(),
danno@chromium.orgc99cd482013-03-21 15:26:42 +00002851 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002852 kSaveFPRegs,
2853 EMIT_REMEMBERED_SET,
2854 check_needed);
2855 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002856
2857 __ bind(&skip_assignment);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002858}
2859
2860
2861void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002862 HObjectAccess access = instr->hydrogen()->access();
2863 int offset = access.offset();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002864 Register object = ToRegister(instr->object());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002865
2866 if (access.IsExternalMemory()) {
2867 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002868 MemOperand operand = MemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002869 __ Load(result, operand, access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002870 return;
2871 }
2872
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002873 if (instr->hydrogen()->representation().IsDouble()) {
2874 DoubleRegister result = ToDoubleRegister(instr->result());
2875 __ ldc1(result, FieldMemOperand(object, offset));
2876 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002877 }
2878
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002879 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002880 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002881 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002882 object = result;
2883 }
2884 MemOperand operand = FieldMemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002885 __ Load(result, operand, access.representation());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002886}
2887
2888
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002889void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002890 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002891 ASSERT(ToRegister(instr->object()).is(a0));
2892 ASSERT(ToRegister(instr->result()).is(v0));
2893
2894 // Name is always in a2.
2895 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002896 Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002897 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2898}
2899
2900
2901void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2902 Register scratch = scratch0();
2903 Register function = ToRegister(instr->function());
2904 Register result = ToRegister(instr->result());
2905
2906 // Check that the function really is a function. Load map into the
2907 // result register.
2908 __ GetObjectType(function, result, scratch);
2909 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_FUNCTION_TYPE));
2910
2911 // Make sure that the function has an instance prototype.
2912 Label non_instance;
2913 __ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
2914 __ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
2915 __ Branch(&non_instance, ne, scratch, Operand(zero_reg));
2916
2917 // Get the prototype or initial map from the function.
2918 __ lw(result,
2919 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2920
2921 // Check that the function has a prototype or an initial map.
2922 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2923 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2924
2925 // If the function does not have an initial map, we're done.
2926 Label done;
2927 __ GetObjectType(result, scratch, scratch);
2928 __ Branch(&done, ne, scratch, Operand(MAP_TYPE));
2929
2930 // Get the prototype from the initial map.
2931 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
2932 __ Branch(&done);
2933
2934 // Non-instance prototype: Fetch prototype from constructor field
2935 // in initial map.
2936 __ bind(&non_instance);
2937 __ lw(result, FieldMemOperand(result, Map::kConstructorOffset));
2938
2939 // All done.
2940 __ bind(&done);
2941}
2942
2943
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002944void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
2945 Register result = ToRegister(instr->result());
2946 __ LoadRoot(result, instr->index());
2947}
2948
2949
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002950void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2951 Register arguments = ToRegister(instr->arguments());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002952 Register result = ToRegister(instr->result());
machenbach@chromium.org90dca012013-11-22 10:04:21 +00002953 // There are two words between the frame pointer and the last argument.
2954 // Subtracting from length accounts for one of them add one more.
2955 if (instr->length()->IsConstantOperand()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002956 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
machenbach@chromium.org90dca012013-11-22 10:04:21 +00002957 if (instr->index()->IsConstantOperand()) {
2958 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2959 int index = (const_length - const_index) + 1;
2960 __ lw(result, MemOperand(arguments, index * kPointerSize));
2961 } else {
2962 Register index = ToRegister(instr->index());
2963 __ li(at, Operand(const_length + 1));
2964 __ Subu(result, at, index);
2965 __ sll(at, result, kPointerSizeLog2);
2966 __ Addu(at, arguments, at);
2967 __ lw(result, MemOperand(at));
2968 }
2969 } else if (instr->index()->IsConstantOperand()) {
2970 Register length = ToRegister(instr->length());
2971 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2972 int loc = const_index - 1;
2973 if (loc != 0) {
2974 __ Subu(result, length, Operand(loc));
2975 __ sll(at, result, kPointerSizeLog2);
2976 __ Addu(at, arguments, at);
2977 __ lw(result, MemOperand(at));
2978 } else {
2979 __ sll(at, length, kPointerSizeLog2);
2980 __ Addu(at, arguments, at);
2981 __ lw(result, MemOperand(at));
2982 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002983 } else {
2984 Register length = ToRegister(instr->length());
2985 Register index = ToRegister(instr->index());
machenbach@chromium.org90dca012013-11-22 10:04:21 +00002986 __ Subu(result, length, index);
2987 __ Addu(result, result, 1);
2988 __ sll(at, result, kPointerSizeLog2);
2989 __ Addu(at, arguments, at);
2990 __ lw(result, MemOperand(at));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002991 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002992}
2993
2994
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002995void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
2996 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002997 Register key = no_reg;
2998 ElementsKind elements_kind = instr->elements_kind();
2999 bool key_is_constant = instr->key()->IsConstantOperand();
3000 int constant_key = 0;
3001 if (key_is_constant) {
3002 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
3003 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003004 Abort(kArrayIndexConstantValueTooBig);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003005 }
3006 } else {
3007 key = ToRegister(instr->key());
3008 }
danno@chromium.org129d3982012-07-25 15:01:47 +00003009 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003010 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00003011 ? (element_size_shift - kSmiTagSize) : element_size_shift;
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003012 int additional_offset = IsFixedTypedArrayElementsKind(elements_kind)
3013 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag
3014 : 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003015
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003016 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003017 elements_kind == FLOAT32_ELEMENTS ||
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003018 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003019 elements_kind == FLOAT64_ELEMENTS) {
3020 int base_offset =
3021 (instr->additional_index() << element_size_shift) + additional_offset;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003022 FPURegister result = ToDoubleRegister(instr->result());
3023 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00003024 __ Addu(scratch0(), external_pointer, constant_key << element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003025 } else {
3026 __ sll(scratch0(), key, shift_size);
3027 __ Addu(scratch0(), scratch0(), external_pointer);
3028 }
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003029 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003030 elements_kind == FLOAT32_ELEMENTS) {
3031 __ lwc1(result, MemOperand(scratch0(), base_offset));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003032 __ cvt_d_s(result, result);
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003033 } else { // loading doubles, not floats.
3034 __ ldc1(result, MemOperand(scratch0(), base_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003035 }
3036 } else {
3037 Register result = ToRegister(instr->result());
danno@chromium.org129d3982012-07-25 15:01:47 +00003038 MemOperand mem_operand = PrepareKeyedOperand(
3039 key, external_pointer, key_is_constant, constant_key,
3040 element_size_shift, shift_size,
3041 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003042 switch (elements_kind) {
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003043 case EXTERNAL_INT8_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003044 case INT8_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003045 __ lb(result, mem_operand);
3046 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003047 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
3048 case EXTERNAL_UINT8_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003049 case UINT8_ELEMENTS:
3050 case UINT8_CLAMPED_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003051 __ lbu(result, mem_operand);
3052 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003053 case EXTERNAL_INT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003054 case INT16_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003055 __ lh(result, mem_operand);
3056 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003057 case EXTERNAL_UINT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003058 case UINT16_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003059 __ lhu(result, mem_operand);
3060 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003061 case EXTERNAL_INT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003062 case INT32_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003063 __ lw(result, mem_operand);
3064 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003065 case EXTERNAL_UINT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003066 case UINT32_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003067 __ lw(result, mem_operand);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003068 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3069 DeoptimizeIf(Ugreater_equal, instr->environment(),
3070 result, Operand(0x80000000));
3071 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003072 break;
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003073 case FLOAT32_ELEMENTS:
3074 case FLOAT64_ELEMENTS:
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00003075 case EXTERNAL_FLOAT32_ELEMENTS:
3076 case EXTERNAL_FLOAT64_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003077 case FAST_DOUBLE_ELEMENTS:
3078 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003079 case FAST_SMI_ELEMENTS:
3080 case FAST_HOLEY_DOUBLE_ELEMENTS:
3081 case FAST_HOLEY_ELEMENTS:
3082 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003083 case DICTIONARY_ELEMENTS:
3084 case NON_STRICT_ARGUMENTS_ELEMENTS:
3085 UNREACHABLE();
3086 break;
3087 }
3088 }
3089}
3090
3091
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003092void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3093 Register elements = ToRegister(instr->elements());
3094 bool key_is_constant = instr->key()->IsConstantOperand();
3095 Register key = no_reg;
3096 DoubleRegister result = ToDoubleRegister(instr->result());
3097 Register scratch = scratch0();
3098
3099 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003100
3101 int base_offset =
3102 FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3103 (instr->additional_index() << element_size_shift);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003104 if (key_is_constant) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003105 int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003106 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003107 Abort(kArrayIndexConstantValueTooBig);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003108 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003109 base_offset += constant_key << element_size_shift;
3110 }
3111 __ Addu(scratch, elements, Operand(base_offset));
3112
3113 if (!key_is_constant) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003114 key = ToRegister(instr->key());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003115 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
3116 ? (element_size_shift - kSmiTagSize) : element_size_shift;
3117 __ sll(at, key, shift_size);
3118 __ Addu(scratch, scratch, at);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003119 }
3120
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003121 __ ldc1(result, MemOperand(scratch));
3122
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003123 if (instr->hydrogen()->RequiresHoleCheck()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003124 __ lw(scratch, MemOperand(scratch, sizeof(kHoleNanLower32)));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003125 DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003126 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003127}
3128
3129
3130void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3131 Register elements = ToRegister(instr->elements());
3132 Register result = ToRegister(instr->result());
3133 Register scratch = scratch0();
3134 Register store_base = scratch;
3135 int offset = 0;
3136
3137 if (instr->key()->IsConstantOperand()) {
3138 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3139 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
3140 instr->additional_index());
3141 store_base = elements;
3142 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003143 Register key = ToRegister(instr->key());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003144 // Even though the HLoadKeyed instruction forces the input
3145 // representation for the key to be an integer, the input gets replaced
3146 // during bound check elimination with the index argument to the bounds
3147 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003148 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003149 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
3150 __ addu(scratch, elements, scratch);
3151 } else {
3152 __ sll(scratch, key, kPointerSizeLog2);
3153 __ addu(scratch, elements, scratch);
3154 }
3155 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
3156 }
3157 __ lw(result, FieldMemOperand(store_base, offset));
3158
3159 // Check for the hole value.
3160 if (instr->hydrogen()->RequiresHoleCheck()) {
3161 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003162 __ SmiTst(result, scratch);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003163 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3164 } else {
3165 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3166 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch));
3167 }
3168 }
3169}
3170
3171
3172void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003173 if (instr->is_typed_elements()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003174 DoLoadKeyedExternalArray(instr);
3175 } else if (instr->hydrogen()->representation().IsDouble()) {
3176 DoLoadKeyedFixedDoubleArray(instr);
3177 } else {
3178 DoLoadKeyedFixedArray(instr);
3179 }
3180}
3181
3182
3183MemOperand LCodeGen::PrepareKeyedOperand(Register key,
3184 Register base,
3185 bool key_is_constant,
3186 int constant_key,
3187 int element_size,
3188 int shift_size,
3189 int additional_index,
3190 int additional_offset) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003191 int base_offset = (additional_index << element_size) + additional_offset;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003192 if (key_is_constant) {
3193 return MemOperand(base,
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00003194 base_offset + (constant_key << element_size));
3195 }
3196
3197 if (additional_offset != 0) {
3198 if (shift_size >= 0) {
3199 __ sll(scratch0(), key, shift_size);
3200 __ Addu(scratch0(), scratch0(), Operand(base_offset));
3201 } else {
3202 ASSERT_EQ(-1, shift_size);
3203 __ srl(scratch0(), key, 1);
3204 __ Addu(scratch0(), scratch0(), Operand(base_offset));
3205 }
3206 __ Addu(scratch0(), base, scratch0());
3207 return MemOperand(scratch0());
3208 }
3209
3210 if (additional_index != 0) {
3211 additional_index *= 1 << (element_size - shift_size);
3212 __ Addu(scratch0(), key, Operand(additional_index));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003213 }
3214
3215 if (additional_index == 0) {
3216 if (shift_size >= 0) {
3217 __ sll(scratch0(), key, shift_size);
3218 __ Addu(scratch0(), base, scratch0());
3219 return MemOperand(scratch0());
3220 } else {
3221 ASSERT_EQ(-1, shift_size);
3222 __ srl(scratch0(), key, 1);
3223 __ Addu(scratch0(), base, scratch0());
3224 return MemOperand(scratch0());
3225 }
3226 }
3227
3228 if (shift_size >= 0) {
3229 __ sll(scratch0(), scratch0(), shift_size);
3230 __ Addu(scratch0(), base, scratch0());
3231 return MemOperand(scratch0());
3232 } else {
3233 ASSERT_EQ(-1, shift_size);
3234 __ srl(scratch0(), scratch0(), 1);
3235 __ Addu(scratch0(), base, scratch0());
3236 return MemOperand(scratch0());
3237 }
3238}
3239
3240
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003241void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003242 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003243 ASSERT(ToRegister(instr->object()).is(a1));
3244 ASSERT(ToRegister(instr->key()).is(a0));
3245
3246 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
3247 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3248}
3249
3250
3251void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3252 Register scratch = scratch0();
3253 Register temp = scratch1();
3254 Register result = ToRegister(instr->result());
3255
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003256 if (instr->hydrogen()->from_inlined()) {
3257 __ Subu(result, sp, 2 * kPointerSize);
3258 } else {
3259 // Check if the calling frame is an arguments adaptor frame.
3260 Label done, adapted;
3261 __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3262 __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
3263 __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003264
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003265 // Result is the frame pointer for the frame if not adapted and for the real
3266 // frame below the adaptor frame if adapted.
3267 __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
3268 __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
3269 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003270}
3271
3272
3273void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003274 Register elem = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003275 Register result = ToRegister(instr->result());
3276
3277 Label done;
3278
3279 // If no arguments adaptor frame the number of arguments is fixed.
3280 __ Addu(result, zero_reg, Operand(scope()->num_parameters()));
3281 __ Branch(&done, eq, fp, Operand(elem));
3282
3283 // Arguments adaptor frame present. Get argument length from there.
3284 __ lw(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3285 __ lw(result,
3286 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
3287 __ SmiUntag(result);
3288
3289 // Argument length is in result register.
3290 __ bind(&done);
3291}
3292
3293
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003294void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003295 Register receiver = ToRegister(instr->receiver());
3296 Register function = ToRegister(instr->function());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003297 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003298 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003299
3300 // If the receiver is null or undefined, we have to pass the global
3301 // object as a receiver to normal functions. Values have to be
3302 // passed unchanged to builtins and strict-mode functions.
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003303 Label global_object, result_in_receiver;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003304
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003305 if (!instr->hydrogen()->known_function()) {
3306 // Do not transform the receiver to object for strict mode
3307 // functions.
3308 __ lw(scratch,
3309 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
3310 __ lw(scratch,
3311 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003312
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003313 // Do not transform the receiver to object for builtins.
3314 int32_t strict_mode_function_mask =
3315 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
3316 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
3317 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask));
3318 __ Branch(&result_in_receiver, ne, scratch, Operand(zero_reg));
3319 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003320
3321 // Normal function. Replace undefined or null with global receiver.
3322 __ LoadRoot(scratch, Heap::kNullValueRootIndex);
3323 __ Branch(&global_object, eq, receiver, Operand(scratch));
3324 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
3325 __ Branch(&global_object, eq, receiver, Operand(scratch));
3326
3327 // Deoptimize if the receiver is not a JS object.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003328 __ SmiTst(receiver, scratch);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003329 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3330
3331 __ GetObjectType(receiver, scratch, scratch);
3332 DeoptimizeIf(lt, instr->environment(),
3333 scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003334
machenbach@chromium.org57a54ac2014-01-31 14:01:53 +00003335 __ Branch(&result_in_receiver);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003336 __ bind(&global_object);
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00003337 __ lw(result, FieldMemOperand(function, JSFunction::kContextOffset));
3338 __ lw(result,
3339 ContextOperand(result, Context::GLOBAL_OBJECT_INDEX));
3340 __ lw(result,
3341 FieldMemOperand(result, GlobalObject::kGlobalReceiverOffset));
ulan@chromium.org0f13e742014-01-03 15:51:11 +00003342
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003343 if (result.is(receiver)) {
3344 __ bind(&result_in_receiver);
3345 } else {
3346 Label result_ok;
3347 __ Branch(&result_ok);
3348 __ bind(&result_in_receiver);
3349 __ mov(result, receiver);
3350 __ bind(&result_ok);
3351 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003352}
3353
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003354
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003355void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3356 Register receiver = ToRegister(instr->receiver());
3357 Register function = ToRegister(instr->function());
3358 Register length = ToRegister(instr->length());
3359 Register elements = ToRegister(instr->elements());
3360 Register scratch = scratch0();
3361 ASSERT(receiver.is(a0)); // Used for parameter count.
3362 ASSERT(function.is(a1)); // Required by InvokeFunction.
3363 ASSERT(ToRegister(instr->result()).is(v0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003364
3365 // Copy the arguments to this function possibly from the
3366 // adaptor frame below it.
3367 const uint32_t kArgumentsLimit = 1 * KB;
3368 DeoptimizeIf(hi, instr->environment(), length, Operand(kArgumentsLimit));
3369
3370 // Push the receiver and use the register to keep the original
3371 // number of arguments.
3372 __ push(receiver);
3373 __ Move(receiver, length);
3374 // The arguments are at a one pointer size offset from elements.
3375 __ Addu(elements, elements, Operand(1 * kPointerSize));
3376
3377 // Loop through the arguments pushing them onto the execution
3378 // stack.
3379 Label invoke, loop;
3380 // length is a small non-negative integer, due to the test above.
3381 __ Branch(USE_DELAY_SLOT, &invoke, eq, length, Operand(zero_reg));
3382 __ sll(scratch, length, 2);
3383 __ bind(&loop);
3384 __ Addu(scratch, elements, scratch);
3385 __ lw(scratch, MemOperand(scratch));
3386 __ push(scratch);
3387 __ Subu(length, length, Operand(1));
3388 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg));
3389 __ sll(scratch, length, 2);
3390
3391 __ bind(&invoke);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00003392 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003393 LPointerMap* pointers = instr->pointer_map();
erikcorry0ad885c2011-11-21 13:51:57 +00003394 SafepointGenerator safepoint_generator(
3395 this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003396 // The number of arguments is stored in receiver which is a0, as expected
3397 // by InvokeFunction.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003398 ParameterCount actual(receiver);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003399 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003400}
3401
3402
3403void LCodeGen::DoPushArgument(LPushArgument* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003404 LOperand* argument = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003405 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003406 Abort(kDoPushArgumentNotImplementedForDoubleType);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003407 } else {
3408 Register argument_reg = EmitLoadRegister(argument, at);
3409 __ push(argument_reg);
3410 }
3411}
3412
3413
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003414void LCodeGen::DoDrop(LDrop* instr) {
3415 __ Drop(instr->count());
3416}
3417
3418
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003419void LCodeGen::DoThisFunction(LThisFunction* instr) {
3420 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003421 __ lw(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003422}
3423
3424
3425void LCodeGen::DoContext(LContext* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003426 // If there is a non-return use, the context must be moved to a register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003427 Register result = ToRegister(instr->result());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003428 if (info()->IsOptimizing()) {
3429 __ lw(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
3430 } else {
3431 // If there is no frame, the context must be in cp.
3432 ASSERT(result.is(cp));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003433 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003434}
3435
3436
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003437void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003438 ASSERT(ToRegister(instr->context()).is(cp));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003439 __ li(scratch0(), instr->hydrogen()->pairs());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003440 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags())));
3441 // The context is the first argument.
3442 __ Push(cp, scratch0(), scratch1());
3443 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3444}
3445
3446
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003447void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003448 int formal_parameter_count,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003449 int arity,
3450 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003451 A1State a1_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003452 bool dont_adapt_arguments =
3453 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3454 bool can_invoke_directly =
3455 dont_adapt_arguments || formal_parameter_count == arity;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003456
3457 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003458
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003459 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003460 if (a1_state == A1_UNINITIALIZED) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003461 __ li(a1, function);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003462 }
3463
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003464 // Change context.
3465 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003466
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003467 // Set r0 to arguments count if adaption is not needed. Assumes that r0
3468 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003469 if (dont_adapt_arguments) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003470 __ li(a0, Operand(arity));
3471 }
3472
3473 // Invoke function.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003474 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
3475 __ Call(at);
3476
3477 // Set up deoptimization.
3478 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3479 } else {
3480 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3481 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003482 ParameterCount expected(formal_parameter_count);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003483 __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003484 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003485}
3486
3487
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003488void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003489 ASSERT(instr->context() != NULL);
3490 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003491 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003492 Register result = ToRegister(instr->result());
3493 Register scratch = scratch0();
3494
3495 // Deoptimize if not a heap number.
3496 __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
3497 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3498 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
3499
3500 Label done;
3501 Register exponent = scratch0();
3502 scratch = no_reg;
3503 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3504 // Check the sign of the argument. If the argument is positive, just
3505 // return it.
3506 __ Move(result, input);
3507 __ And(at, exponent, Operand(HeapNumber::kSignMask));
3508 __ Branch(&done, eq, at, Operand(zero_reg));
3509
3510 // Input is negative. Reverse its sign.
3511 // Preserve the value of all registers.
3512 {
3513 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3514
3515 // Registers were saved at the safepoint, so we can use
3516 // many scratch registers.
3517 Register tmp1 = input.is(a1) ? a0 : a1;
3518 Register tmp2 = input.is(a2) ? a0 : a2;
3519 Register tmp3 = input.is(a3) ? a0 : a3;
3520 Register tmp4 = input.is(t0) ? a0 : t0;
3521
3522 // exponent: floating point exponent value.
3523
3524 Label allocated, slow;
3525 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
3526 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
3527 __ Branch(&allocated);
3528
3529 // Slow case: Call the runtime system to do the number allocation.
3530 __ bind(&slow);
3531
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003532 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr,
3533 instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003534 // Set the pointer to the new heap number in tmp.
3535 if (!tmp1.is(v0))
3536 __ mov(tmp1, v0);
3537 // Restore input_reg after call to runtime.
3538 __ LoadFromSafepointRegisterSlot(input, input);
3539 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3540
3541 __ bind(&allocated);
3542 // exponent: floating point exponent value.
3543 // tmp1: allocated heap number.
3544 __ And(exponent, exponent, Operand(~HeapNumber::kSignMask));
3545 __ sw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
3546 __ lw(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
3547 __ sw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
3548
3549 __ StoreToSafepointRegisterSlot(tmp1, result);
3550 }
3551
3552 __ bind(&done);
3553}
3554
3555
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003556void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003557 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003558 Register result = ToRegister(instr->result());
3559 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
3560 Label done;
3561 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg));
3562 __ mov(result, input);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003563 __ subu(result, zero_reg, input);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003564 // Overflow if result is still negative, i.e. 0x80000000.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003565 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
3566 __ bind(&done);
3567}
3568
3569
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003570void LCodeGen::DoMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003571 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003572 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003573 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003574 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003575 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003576 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003577 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3578 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003579 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003580 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003581 LMathAbs* instr_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003582 };
3583
3584 Representation r = instr->hydrogen()->value()->representation();
3585 if (r.IsDouble()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003586 FPURegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003587 FPURegister result = ToDoubleRegister(instr->result());
3588 __ abs_d(result, input);
danno@chromium.org59400602013-08-13 17:09:37 +00003589 } else if (r.IsSmiOrInteger32()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003590 EmitIntegerMathAbs(instr);
3591 } else {
3592 // Representation is tagged.
3593 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003594 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003595 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003596 // Smi check.
3597 __ JumpIfNotSmi(input, deferred->entry());
3598 // If smi, handle it directly.
3599 EmitIntegerMathAbs(instr);
3600 __ bind(deferred->exit());
3601 }
3602}
3603
3604
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003605void LCodeGen::DoMathFloor(LMathFloor* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003606 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003607 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003608 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003609 Register except_flag = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003610
3611 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003612 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003613 input,
3614 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003615 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003616 except_flag);
3617
3618 // Deopt if the operation did not succeed.
3619 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3620
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003621 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3622 // Test for -0.
3623 Label done;
3624 __ Branch(&done, ne, result, Operand(zero_reg));
3625 __ mfc1(scratch1, input.high());
3626 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
3627 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
3628 __ bind(&done);
3629 }
3630}
3631
3632
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003633void LCodeGen::DoMathRound(LMathRound* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003634 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003635 Register result = ToRegister(instr->result());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003636 DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003637 Register scratch = scratch0();
3638 Label done, check_sign_on_zero;
3639
3640 // Extract exponent bits.
3641 __ mfc1(result, input.high());
3642 __ Ext(scratch,
3643 result,
3644 HeapNumber::kExponentShift,
3645 HeapNumber::kExponentBits);
3646
3647 // If the number is in ]-0.5, +0.5[, the result is +/- 0.
3648 Label skip1;
3649 __ Branch(&skip1, gt, scratch, Operand(HeapNumber::kExponentBias - 2));
3650 __ mov(result, zero_reg);
3651 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3652 __ Branch(&check_sign_on_zero);
3653 } else {
3654 __ Branch(&done);
3655 }
3656 __ bind(&skip1);
3657
3658 // The following conversion will not work with numbers
3659 // outside of ]-2^32, 2^32[.
3660 DeoptimizeIf(ge, instr->environment(), scratch,
3661 Operand(HeapNumber::kExponentBias + 32));
3662
3663 // Save the original sign for later comparison.
3664 __ And(scratch, result, Operand(HeapNumber::kSignMask));
3665
3666 __ Move(double_scratch0(), 0.5);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003667 __ add_d(double_scratch0(), input, double_scratch0());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003668
3669 // Check sign of the result: if the sign changed, the input
3670 // value was in ]0.5, 0[ and the result should be -0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003671 __ mfc1(result, double_scratch0().high());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003672 __ Xor(result, result, Operand(scratch));
3673 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3674 // ARM uses 'mi' here, which is 'lt'
3675 DeoptimizeIf(lt, instr->environment(), result,
3676 Operand(zero_reg));
3677 } else {
3678 Label skip2;
3679 // ARM uses 'mi' here, which is 'lt'
3680 // Negating it results in 'ge'
3681 __ Branch(&skip2, ge, result, Operand(zero_reg));
3682 __ mov(result, zero_reg);
3683 __ Branch(&done);
3684 __ bind(&skip2);
3685 }
3686
3687 Register except_flag = scratch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003688 __ EmitFPUTruncate(kRoundToMinusInf,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003689 result,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003690 double_scratch0(),
3691 at,
3692 double_scratch1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003693 except_flag);
3694
3695 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3696
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003697 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3698 // Test for -0.
3699 __ Branch(&done, ne, result, Operand(zero_reg));
3700 __ bind(&check_sign_on_zero);
3701 __ mfc1(scratch, input.high());
3702 __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
3703 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3704 }
3705 __ bind(&done);
3706}
3707
3708
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003709void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003710 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003711 DoubleRegister result = ToDoubleRegister(instr->result());
3712 __ sqrt_d(result, input);
3713}
3714
3715
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003716void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003717 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003718 DoubleRegister result = ToDoubleRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003719 DoubleRegister temp = ToDoubleRegister(instr->temp());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003720
3721 ASSERT(!input.is(result));
3722
3723 // Note that according to ECMA-262 15.8.2.13:
3724 // Math.pow(-Infinity, 0.5) == Infinity
3725 // Math.sqrt(-Infinity) == NaN
3726 Label done;
3727 __ Move(temp, -V8_INFINITY);
3728 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
3729 // Set up Infinity in the delay slot.
3730 // result is overwritten if the branch is not taken.
3731 __ neg_d(result, temp);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003732
3733 // Add +0 to convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003734 __ add_d(result, input, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003735 __ sqrt_d(result, result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003736 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003737}
3738
3739
3740void LCodeGen::DoPower(LPower* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003741 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003742 // Having marked this as a call, we can use any registers.
3743 // Just make sure that the input/output registers are the expected ones.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003744 ASSERT(!instr->right()->IsDoubleRegister() ||
3745 ToDoubleRegister(instr->right()).is(f4));
3746 ASSERT(!instr->right()->IsRegister() ||
3747 ToRegister(instr->right()).is(a2));
3748 ASSERT(ToDoubleRegister(instr->left()).is(f2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003749 ASSERT(ToDoubleRegister(instr->result()).is(f0));
3750
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003751 if (exponent_type.IsSmi()) {
3752 MathPowStub stub(MathPowStub::TAGGED);
3753 __ CallStub(&stub);
3754 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003755 Label no_deopt;
3756 __ JumpIfSmi(a2, &no_deopt);
3757 __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset));
3758 DeoptimizeIf(ne, instr->environment(), t3, Operand(at));
3759 __ bind(&no_deopt);
3760 MathPowStub stub(MathPowStub::TAGGED);
3761 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003762 } else if (exponent_type.IsInteger32()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003763 MathPowStub stub(MathPowStub::INTEGER);
3764 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003765 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003766 ASSERT(exponent_type.IsDouble());
3767 MathPowStub stub(MathPowStub::DOUBLE);
3768 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003769 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003770}
3771
3772
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003773void LCodeGen::DoMathExp(LMathExp* instr) {
3774 DoubleRegister input = ToDoubleRegister(instr->value());
3775 DoubleRegister result = ToDoubleRegister(instr->result());
3776 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
3777 DoubleRegister double_scratch2 = double_scratch0();
3778 Register temp1 = ToRegister(instr->temp1());
3779 Register temp2 = ToRegister(instr->temp2());
3780
3781 MathExpGenerator::EmitMathExp(
3782 masm(), input, result, double_scratch1, double_scratch2,
3783 temp1, temp2, scratch0());
3784}
3785
3786
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003787void LCodeGen::DoMathLog(LMathLog* instr) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003788 __ PrepareCallCFunction(0, 1, scratch0());
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00003789 __ MovToFloatParameter(ToDoubleRegister(instr->value()));
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003790 __ CallCFunction(ExternalReference::math_log_double_function(isolate()),
3791 0, 1);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00003792 __ MovFromFloatResult(ToDoubleRegister(instr->result()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003793}
3794
3795
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003796void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003797 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003798 ASSERT(ToRegister(instr->function()).is(a1));
3799 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003800
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003801 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3802 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003803 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003804 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3805 ParameterCount count(instr->arity());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003806 __ InvokeFunction(a1, count, CALL_FUNCTION, generator);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003807 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003808 CallKnownFunction(known_function,
3809 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003810 instr->arity(),
3811 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003812 A1_CONTAINS_TARGET);
3813 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003814}
3815
3816
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003817void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003818 ASSERT(ToRegister(instr->result()).is(v0));
3819
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003820 LPointerMap* pointers = instr->pointer_map();
3821 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3822
3823 if (instr->target()->IsConstantOperand()) {
3824 LConstantOperand* target = LConstantOperand::cast(instr->target());
3825 Handle<Code> code = Handle<Code>::cast(ToHandle(target));
3826 generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
3827 __ Call(code, RelocInfo::CODE_TARGET);
3828 } else {
3829 ASSERT(instr->target()->IsRegister());
3830 Register target = ToRegister(instr->target());
3831 generator.BeforeCall(__ CallSize(target));
3832 __ Addu(target, target, Operand(Code::kHeaderSize - kHeapObjectTag));
3833 __ Call(target);
3834 }
3835 generator.AfterCall();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003836}
3837
3838
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003839void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
3840 ASSERT(ToRegister(instr->function()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003841 ASSERT(ToRegister(instr->result()).is(v0));
3842
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +00003843 if (instr->hydrogen()->pass_argument_count()) {
3844 __ li(a0, Operand(instr->arity()));
3845 }
3846
3847 // Change context.
3848 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
3849
3850 // Load the code entry address
3851 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
3852 __ Call(at);
3853
3854 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003855}
3856
3857
3858void LCodeGen::DoCallFunction(LCallFunction* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003859 ASSERT(ToRegister(instr->context()).is(cp));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003860 ASSERT(ToRegister(instr->function()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003861 ASSERT(ToRegister(instr->result()).is(v0));
3862
3863 int arity = instr->arity();
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00003864 CallFunctionStub stub(arity, instr->hydrogen()->function_flags());
3865 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003866}
3867
3868
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003869void LCodeGen::DoCallNew(LCallNew* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003870 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003871 ASSERT(ToRegister(instr->constructor()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003872 ASSERT(ToRegister(instr->result()).is(v0));
3873
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003874 __ li(a0, Operand(instr->arity()));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003875 // No cell in a2 for construct type feedback in optimized code
3876 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
3877 __ li(a2, Operand(undefined_value));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003878 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003879 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003880}
3881
3882
ulan@chromium.org750145a2013-03-07 15:14:13 +00003883void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003884 ASSERT(ToRegister(instr->context()).is(cp));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003885 ASSERT(ToRegister(instr->constructor()).is(a1));
3886 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003887
3888 __ li(a0, Operand(instr->arity()));
machenbach@chromium.orgc8cbc432014-01-21 09:01:57 +00003889 __ li(a2, Operand(factory()->undefined_value()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003890 ElementsKind kind = instr->hydrogen()->elements_kind();
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00003891 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00003892 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00003893 ? DISABLE_ALLOCATION_SITES
3894 : DONT_OVERRIDE;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003895
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003896 if (instr->arity() == 0) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003897 ArrayNoArgumentConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003898 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3899 } else if (instr->arity() == 1) {
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003900 Label done;
3901 if (IsFastPackedElementsKind(kind)) {
3902 Label packed_case;
3903 // We might need a change here,
3904 // look at the first argument.
3905 __ lw(t1, MemOperand(sp, 0));
3906 __ Branch(&packed_case, eq, t1, Operand(zero_reg));
3907
3908 ElementsKind holey_kind = GetHoleyElementsKind(kind);
machenbach@chromium.org03453962014-01-10 14:16:31 +00003909 ArraySingleArgumentConstructorStub stub(holey_kind, override_mode);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003910 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3911 __ jmp(&done);
3912 __ bind(&packed_case);
3913 }
3914
machenbach@chromium.org03453962014-01-10 14:16:31 +00003915 ArraySingleArgumentConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003916 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003917 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003918 } else {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003919 ArrayNArgumentsConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003920 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3921 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00003922}
3923
3924
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003925void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
3926 CallRuntime(instr->function(), instr->arity(), instr);
3927}
3928
3929
verwaest@chromium.org662436e2013-08-28 08:41:27 +00003930void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
3931 Register function = ToRegister(instr->function());
3932 Register code_object = ToRegister(instr->code_object());
3933 __ Addu(code_object, code_object,
3934 Operand(Code::kHeaderSize - kHeapObjectTag));
3935 __ sw(code_object,
3936 FieldMemOperand(function, JSFunction::kCodeEntryOffset));
3937}
3938
3939
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003940void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3941 Register result = ToRegister(instr->result());
3942 Register base = ToRegister(instr->base_object());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003943 if (instr->offset()->IsConstantOperand()) {
3944 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
3945 __ Addu(result, base, Operand(ToInteger32(offset)));
3946 } else {
3947 Register offset = ToRegister(instr->offset());
3948 __ Addu(result, base, offset);
3949 }
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003950}
3951
3952
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003953void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003954 Representation representation = instr->representation();
3955
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003956 Register object = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003957 Register scratch = scratch0();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003958 HObjectAccess access = instr->hydrogen()->access();
3959 int offset = access.offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003960
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003961 if (access.IsExternalMemory()) {
3962 Register value = ToRegister(instr->value());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00003963 MemOperand operand = MemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00003964 __ Store(value, operand, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00003965 return;
3966 }
3967
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003968 Handle<Map> transition = instr->transition();
3969
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003970 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003971 Register value = ToRegister(instr->value());
3972 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003973 __ SmiTst(value, scratch);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003974 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3975 }
machenbach@chromium.org09cae8d2014-01-30 01:05:27 +00003976 } else if (representation.IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003977 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003978 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003979 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3980 DoubleRegister value = ToDoubleRegister(instr->value());
3981 __ sdc1(value, FieldMemOperand(object, offset));
3982 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003983 }
3984
danno@chromium.orgf005df62013-04-30 16:36:45 +00003985 if (!transition.is_null()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003986 __ li(scratch, Operand(transition));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003987 __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +00003988 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003989 Register temp = ToRegister(instr->temp());
verwaest@chromium.org37141392012-05-31 13:27:02 +00003990 // Update the write barrier for the map field.
3991 __ RecordWriteField(object,
3992 HeapObject::kMapOffset,
3993 scratch,
3994 temp,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003995 GetRAState(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00003996 kSaveFPRegs,
3997 OMIT_REMEMBERED_SET,
3998 OMIT_SMI_CHECK);
3999 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004000 }
4001
4002 // Do the store.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004003 Register value = ToRegister(instr->value());
4004 ASSERT(!object.is(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004005 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004006 instr->hydrogen()->value()->IsHeapObject()
4007 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004008 if (access.IsInobject()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004009 MemOperand operand = FieldMemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004010 __ Store(value, operand, representation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004011 if (instr->hydrogen()->NeedsWriteBarrier()) {
4012 // Update the write barrier for the object for in-object properties.
4013 __ RecordWriteField(object,
4014 offset,
4015 value,
4016 scratch,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004017 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004018 kSaveFPRegs,
4019 EMIT_REMEMBERED_SET,
4020 check_needed);
4021 }
4022 } else {
4023 __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004024 MemOperand operand = FieldMemOperand(scratch, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004025 __ Store(value, operand, representation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004026 if (instr->hydrogen()->NeedsWriteBarrier()) {
4027 // Update the write barrier for the properties array.
4028 // object is used as a scratch register.
4029 __ RecordWriteField(scratch,
4030 offset,
4031 value,
4032 object,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004033 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004034 kSaveFPRegs,
4035 EMIT_REMEMBERED_SET,
4036 check_needed);
4037 }
4038 }
4039}
4040
4041
4042void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004043 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004044 ASSERT(ToRegister(instr->object()).is(a1));
4045 ASSERT(ToRegister(instr->value()).is(a0));
4046
4047 // Name is always in a2.
4048 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004049 Handle<Code> ic = StoreIC::initialize_stub(isolate(),
machenbach@chromium.org43c51e52014-01-20 07:57:28 +00004050 instr->strict_mode_flag());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004051 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4052}
4053
4054
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004055void LCodeGen::ApplyCheckIf(Condition condition,
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004056 LBoundsCheck* check,
4057 Register src1,
4058 const Operand& src2) {
4059 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4060 Label done;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004061 __ Branch(&done, NegateCondition(condition), src1, src2);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004062 __ stop("eliminated bounds check failed");
4063 __ bind(&done);
4064 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004065 DeoptimizeIf(condition, check->environment(), src1, src2);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004066 }
4067}
4068
4069
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004070void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004071 if (instr->hydrogen()->skip_check()) return;
4072
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004073 Condition condition = instr->hydrogen()->allow_equality() ? hi : hs;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004074 if (instr->index()->IsConstantOperand()) {
4075 int constant_index =
4076 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004077 if (instr->hydrogen()->length()->representation().IsSmi()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004078 __ li(at, Operand(Smi::FromInt(constant_index)));
4079 } else {
4080 __ li(at, Operand(constant_index));
4081 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004082 ApplyCheckIf(condition,
4083 instr,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004084 at,
4085 Operand(ToRegister(instr->length())));
4086 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004087 ApplyCheckIf(condition,
4088 instr,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004089 ToRegister(instr->index()),
4090 Operand(ToRegister(instr->length())));
4091 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004092}
4093
4094
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004095void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4096 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004097 Register key = no_reg;
4098 ElementsKind elements_kind = instr->elements_kind();
4099 bool key_is_constant = instr->key()->IsConstantOperand();
4100 int constant_key = 0;
4101 if (key_is_constant) {
4102 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4103 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00004104 Abort(kArrayIndexConstantValueTooBig);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004105 }
4106 } else {
4107 key = ToRegister(instr->key());
4108 }
danno@chromium.org129d3982012-07-25 15:01:47 +00004109 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004110 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00004111 ? (element_size_shift - kSmiTagSize) : element_size_shift;
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004112 int additional_offset = IsFixedTypedArrayElementsKind(elements_kind)
4113 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag
4114 : 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004115
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004116 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004117 elements_kind == FLOAT32_ELEMENTS ||
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004118 elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004119 elements_kind == FLOAT64_ELEMENTS) {
4120 int base_offset =
4121 (instr->additional_index() << element_size_shift) + additional_offset;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004122 Register address = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004123 FPURegister value(ToDoubleRegister(instr->value()));
4124 if (key_is_constant) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004125 if (constant_key != 0) {
4126 __ Addu(address, external_pointer,
4127 Operand(constant_key << element_size_shift));
4128 } else {
4129 address = external_pointer;
4130 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004131 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004132 __ sll(address, key, shift_size);
4133 __ Addu(address, external_pointer, address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004134 }
4135
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004136 if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004137 elements_kind == FLOAT32_ELEMENTS) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004138 __ cvt_s_d(double_scratch0(), value);
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004139 __ swc1(double_scratch0(), MemOperand(address, base_offset));
4140 } else { // Storing doubles, not floats.
4141 __ sdc1(value, MemOperand(address, base_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004142 }
4143 } else {
4144 Register value(ToRegister(instr->value()));
danno@chromium.org129d3982012-07-25 15:01:47 +00004145 MemOperand mem_operand = PrepareKeyedOperand(
4146 key, external_pointer, key_is_constant, constant_key,
4147 element_size_shift, shift_size,
4148 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004149 switch (elements_kind) {
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004150 case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
4151 case EXTERNAL_INT8_ELEMENTS:
4152 case EXTERNAL_UINT8_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004153 case UINT8_ELEMENTS:
4154 case UINT8_CLAMPED_ELEMENTS:
4155 case INT8_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004156 __ sb(value, mem_operand);
4157 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004158 case EXTERNAL_INT16_ELEMENTS:
4159 case EXTERNAL_UINT16_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004160 case INT16_ELEMENTS:
4161 case UINT16_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004162 __ sh(value, mem_operand);
4163 break;
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004164 case EXTERNAL_INT32_ELEMENTS:
4165 case EXTERNAL_UINT32_ELEMENTS:
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004166 case INT32_ELEMENTS:
4167 case UINT32_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004168 __ sw(value, mem_operand);
4169 break;
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004170 case FLOAT32_ELEMENTS:
4171 case FLOAT64_ELEMENTS:
machenbach@chromium.orgaf4fba32014-01-27 01:05:32 +00004172 case EXTERNAL_FLOAT32_ELEMENTS:
4173 case EXTERNAL_FLOAT64_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004174 case FAST_DOUBLE_ELEMENTS:
4175 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004176 case FAST_SMI_ELEMENTS:
4177 case FAST_HOLEY_DOUBLE_ELEMENTS:
4178 case FAST_HOLEY_ELEMENTS:
4179 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004180 case DICTIONARY_ELEMENTS:
4181 case NON_STRICT_ARGUMENTS_ELEMENTS:
4182 UNREACHABLE();
4183 break;
4184 }
4185 }
4186}
4187
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004188
4189void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4190 DoubleRegister value = ToDoubleRegister(instr->value());
4191 Register elements = ToRegister(instr->elements());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004192 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004193 DoubleRegister double_scratch = double_scratch0();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004194 bool key_is_constant = instr->key()->IsConstantOperand();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004195 Label not_nan, done;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004196
4197 // Calculate the effective address of the slot in the array to store the
4198 // double value.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004199 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004200 if (key_is_constant) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004201 int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004202 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00004203 Abort(kArrayIndexConstantValueTooBig);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004204 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004205 __ Addu(scratch, elements,
4206 Operand((constant_key << element_size_shift) +
4207 FixedDoubleArray::kHeaderSize - kHeapObjectTag));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004208 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004209 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
4210 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4211 __ Addu(scratch, elements,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004212 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004213 __ sll(at, ToRegister(instr->key()), shift_size);
4214 __ Addu(scratch, scratch, at);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004215 }
4216
4217 if (instr->NeedsCanonicalization()) {
4218 Label is_nan;
4219 // Check for NaN. All NaNs must be canonicalized.
4220 __ BranchF(NULL, &is_nan, eq, value, value);
4221 __ Branch(&not_nan);
4222
4223 // Only load canonical NaN if the comparison above set the overflow.
4224 __ bind(&is_nan);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004225 __ Move(double_scratch,
4226 FixedDoubleArray::canonical_not_the_hole_nan_as_double());
4227 __ sdc1(double_scratch, MemOperand(scratch, instr->additional_index() <<
4228 element_size_shift));
4229 __ Branch(&done);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004230 }
4231
4232 __ bind(&not_nan);
4233 __ sdc1(value, MemOperand(scratch, instr->additional_index() <<
4234 element_size_shift));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004235 __ bind(&done);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004236}
4237
4238
4239void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4240 Register value = ToRegister(instr->value());
4241 Register elements = ToRegister(instr->elements());
4242 Register key = instr->key()->IsRegister() ? ToRegister(instr->key())
4243 : no_reg;
4244 Register scratch = scratch0();
4245 Register store_base = scratch;
4246 int offset = 0;
4247
4248 // Do the store.
4249 if (instr->key()->IsConstantOperand()) {
4250 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4251 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
4252 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
4253 instr->additional_index());
4254 store_base = elements;
4255 } else {
4256 // Even though the HLoadKeyed instruction forces the input
4257 // representation for the key to be an integer, the input gets replaced
4258 // during bound check elimination with the index argument to the bounds
4259 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004260 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004261 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
4262 __ addu(scratch, elements, scratch);
4263 } else {
4264 __ sll(scratch, key, kPointerSizeLog2);
4265 __ addu(scratch, elements, scratch);
4266 }
4267 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
4268 }
4269 __ sw(value, FieldMemOperand(store_base, offset));
4270
4271 if (instr->hydrogen()->NeedsWriteBarrier()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004272 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004273 instr->hydrogen()->value()->IsHeapObject()
4274 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004275 // Compute address of modified element and store it into key register.
4276 __ Addu(key, store_base, Operand(offset - kHeapObjectTag));
4277 __ RecordWrite(elements,
4278 key,
4279 value,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004280 GetRAState(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004281 kSaveFPRegs,
4282 EMIT_REMEMBERED_SET,
4283 check_needed);
4284 }
4285}
4286
4287
4288void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4289 // By cases: external, fast double
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00004290 if (instr->is_typed_elements()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004291 DoStoreKeyedExternalArray(instr);
4292 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4293 DoStoreKeyedFixedDoubleArray(instr);
4294 } else {
4295 DoStoreKeyedFixedArray(instr);
4296 }
4297}
4298
4299
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004300void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004301 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004302 ASSERT(ToRegister(instr->object()).is(a2));
4303 ASSERT(ToRegister(instr->key()).is(a1));
4304 ASSERT(ToRegister(instr->value()).is(a0));
4305
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004306 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004307 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4308 : isolate()->builtins()->KeyedStoreIC_Initialize();
4309 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4310}
4311
4312
4313void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4314 Register object_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004315 Register scratch = scratch0();
4316
4317 Handle<Map> from_map = instr->original_map();
4318 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004319 ElementsKind from_kind = instr->from_kind();
4320 ElementsKind to_kind = instr->to_kind();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004322 Label not_applicable;
4323 __ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4324 __ Branch(&not_applicable, ne, scratch, Operand(from_map));
4325
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004326 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004327 Register new_map_reg = ToRegister(instr->new_map_temp());
4328 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004329 __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4330 // Write barrier.
4331 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004332 scratch, GetRAState(), kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004333 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004334 ASSERT(ToRegister(instr->context()).is(cp));
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004335 PushSafepointRegistersScope scope(
4336 this, Safepoint::kWithRegistersAndDoubles);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004337 __ mov(a0, object_reg);
4338 __ li(a1, Operand(to_map));
4339 TransitionElementsKindStub stub(from_kind, to_kind);
4340 __ CallStub(&stub);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004341 RecordSafepointWithRegistersAndDoubles(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004342 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004343 }
4344 __ bind(&not_applicable);
4345}
4346
4347
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004348void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4349 Register object = ToRegister(instr->object());
4350 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004351 Label no_memento_found;
4352 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found,
4353 ne, &no_memento_found);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004354 DeoptimizeIf(al, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004355 __ bind(&no_memento_found);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004356}
4357
4358
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004359void LCodeGen::DoStringAdd(LStringAdd* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004360 ASSERT(ToRegister(instr->context()).is(cp));
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00004361 ASSERT(ToRegister(instr->left()).is(a1));
4362 ASSERT(ToRegister(instr->right()).is(a0));
4363 StringAddStub stub(instr->hydrogen()->flags(),
machenbach@chromium.org05150ab2014-01-29 08:13:29 +00004364 instr->hydrogen()->pretenure_flag());
machenbach@chromium.orgbbbda922014-01-23 09:38:20 +00004365 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004366}
4367
4368
4369void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004370 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004371 public:
4372 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4373 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004374 virtual void Generate() V8_OVERRIDE {
4375 codegen()->DoDeferredStringCharCodeAt(instr_);
4376 }
4377 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004378 private:
4379 LStringCharCodeAt* instr_;
4380 };
4381
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004382 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004383 new(zone()) DeferredStringCharCodeAt(this, instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004384 StringCharLoadGenerator::Generate(masm(),
4385 ToRegister(instr->string()),
4386 ToRegister(instr->index()),
4387 ToRegister(instr->result()),
4388 deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004389 __ bind(deferred->exit());
4390}
4391
4392
4393void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4394 Register string = ToRegister(instr->string());
4395 Register result = ToRegister(instr->result());
4396 Register scratch = scratch0();
4397
4398 // TODO(3095996): Get rid of this. For now, we need to make the
4399 // result register contain a valid pointer because it is already
4400 // contained in the register pointer map.
4401 __ mov(result, zero_reg);
4402
4403 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4404 __ push(string);
4405 // Push the index as a smi. This is safe because of the checks in
4406 // DoStringCharCodeAt above.
4407 if (instr->index()->IsConstantOperand()) {
4408 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4409 __ Addu(scratch, zero_reg, Operand(Smi::FromInt(const_index)));
4410 __ push(scratch);
4411 } else {
4412 Register index = ToRegister(instr->index());
4413 __ SmiTag(index);
4414 __ push(index);
4415 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004416 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr,
4417 instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004418 __ AssertSmi(v0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004419 __ SmiUntag(v0);
4420 __ StoreToSafepointRegisterSlot(v0, result);
4421}
4422
4423
4424void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004425 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004426 public:
4427 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4428 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004429 virtual void Generate() V8_OVERRIDE {
4430 codegen()->DoDeferredStringCharFromCode(instr_);
4431 }
4432 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004433 private:
4434 LStringCharFromCode* instr_;
4435 };
4436
4437 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004438 new(zone()) DeferredStringCharFromCode(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004439
4440 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4441 Register char_code = ToRegister(instr->char_code());
4442 Register result = ToRegister(instr->result());
4443 Register scratch = scratch0();
4444 ASSERT(!char_code.is(result));
4445
4446 __ Branch(deferred->entry(), hi,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004447 char_code, Operand(String::kMaxOneByteCharCode));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004448 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4449 __ sll(scratch, char_code, kPointerSizeLog2);
4450 __ Addu(result, result, scratch);
4451 __ lw(result, FieldMemOperand(result, FixedArray::kHeaderSize));
4452 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
4453 __ Branch(deferred->entry(), eq, result, Operand(scratch));
4454 __ bind(deferred->exit());
4455}
4456
4457
4458void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4459 Register char_code = ToRegister(instr->char_code());
4460 Register result = ToRegister(instr->result());
4461
4462 // TODO(3095996): Get rid of this. For now, we need to make the
4463 // result register contain a valid pointer because it is already
4464 // contained in the register pointer map.
4465 __ mov(result, zero_reg);
4466
4467 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4468 __ SmiTag(char_code);
4469 __ push(char_code);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004470 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004471 __ StoreToSafepointRegisterSlot(v0, result);
4472}
4473
4474
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004475void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004476 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004477 ASSERT(input->IsRegister() || input->IsStackSlot());
4478 LOperand* output = instr->result();
4479 ASSERT(output->IsDoubleRegister());
4480 FPURegister single_scratch = double_scratch0().low();
4481 if (input->IsStackSlot()) {
4482 Register scratch = scratch0();
4483 __ lw(scratch, ToMemOperand(input));
4484 __ mtc1(scratch, single_scratch);
4485 } else {
4486 __ mtc1(ToRegister(input), single_scratch);
4487 }
4488 __ cvt_d_w(ToDoubleRegister(output), single_scratch);
4489}
4490
4491
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004492void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4493 LOperand* input = instr->value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004494 LOperand* output = instr->result();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004495 Register scratch = scratch0();
4496
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004497 ASSERT(output->IsRegister());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004498 if (!instr->hydrogen()->value()->HasRange() ||
4499 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004500 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004501 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004502 } else {
4503 __ SmiTag(ToRegister(output), ToRegister(input));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004504 }
4505}
4506
4507
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004508void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004509 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004510 LOperand* output = instr->result();
4511
4512 FPURegister dbl_scratch = double_scratch0();
4513 __ mtc1(ToRegister(input), dbl_scratch);
4514 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22);
4515}
4516
4517
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004518void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4519 LOperand* input = instr->value();
4520 LOperand* output = instr->result();
4521 if (!instr->hydrogen()->value()->HasRange() ||
4522 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4523 Register scratch = scratch0();
4524 __ And(scratch, ToRegister(input), Operand(0xc0000000));
4525 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4526 }
4527 __ SmiTag(ToRegister(output), ToRegister(input));
4528}
4529
4530
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004531void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004532 class DeferredNumberTagI V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004533 public:
4534 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4535 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004536 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004537 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004538 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004539 SIGNED_INT32);
4540 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004541 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004542 private:
4543 LNumberTagI* instr_;
4544 };
4545
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004546 Register src = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004547 Register dst = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004548 Register overflow = scratch0();
4549
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004550 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004551 __ SmiTagCheckOverflow(dst, src, overflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004552 __ BranchOnOverflow(deferred->entry(), overflow);
4553 __ bind(deferred->exit());
4554}
4555
4556
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004557void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004558 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004559 public:
4560 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4561 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004562 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004563 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004564 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004565 UNSIGNED_INT32);
4566 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004567 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004568 private:
4569 LNumberTagU* instr_;
4570 };
4571
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004572 Register input = ToRegister(instr->value());
4573 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004574
4575 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004576 __ Branch(deferred->entry(), hi, input, Operand(Smi::kMaxValue));
4577 __ SmiTag(result, input);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004578 __ bind(deferred->exit());
4579}
4580
4581
4582void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4583 LOperand* value,
4584 IntegerSignedness signedness) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004585 Label slow;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004586 Register src = ToRegister(value);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004587 Register dst = ToRegister(instr->result());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004588 DoubleRegister dbl_scratch = double_scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004589
4590 // Preserve the value of all registers.
4591 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4592
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004593 Label done;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004594 if (signedness == SIGNED_INT32) {
4595 // There was overflow, so bits 30 and 31 of the original integer
4596 // disagree. Try to allocate a heap number in new space and store
4597 // the value in there. If that fails, call the runtime system.
4598 if (dst.is(src)) {
4599 __ SmiUntag(src, dst);
4600 __ Xor(src, src, Operand(0x80000000));
4601 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004602 __ mtc1(src, dbl_scratch);
4603 __ cvt_d_w(dbl_scratch, dbl_scratch);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004604 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004605 __ mtc1(src, dbl_scratch);
4606 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004607 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004608
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004609 if (FLAG_inline_new) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004610 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
4611 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004612 __ Move(dst, t1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004613 __ Branch(&done);
4614 }
4615
4616 // Slow case: Call the runtime system to do the number allocation.
4617 __ bind(&slow);
4618
4619 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4620 // register is stored, as this register is in the pointer map, but contains an
4621 // integer value.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004622 __ StoreToSafepointRegisterSlot(zero_reg, dst);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004623 // NumberTagI and NumberTagD use the context from the frame, rather than
4624 // the environment's HContext or HInlinedContext value.
4625 // They only call Runtime::kAllocateHeapNumber.
4626 // The corresponding HChange instructions are added in a phase that does
4627 // not have easy access to the local context.
4628 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4629 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4630 RecordSafepointWithRegisters(
4631 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004632 __ Move(dst, v0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004633 __ Subu(dst, dst, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004634
4635 // Done. Put the value in dbl_scratch into the value of the allocated heap
4636 // number.
4637 __ bind(&done);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004638 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004639 __ Addu(dst, dst, kHeapObjectTag);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004640 __ StoreToSafepointRegisterSlot(dst, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004641}
4642
4643
4644void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004645 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004646 public:
4647 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4648 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004649 virtual void Generate() V8_OVERRIDE {
4650 codegen()->DoDeferredNumberTagD(instr_);
4651 }
4652 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004653 private:
4654 LNumberTagD* instr_;
4655 };
4656
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004657 DoubleRegister input_reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004658 Register scratch = scratch0();
4659 Register reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004660 Register temp1 = ToRegister(instr->temp());
4661 Register temp2 = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004662
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004663 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004664 if (FLAG_inline_new) {
4665 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004666 // We want the untagged address first for performance
4667 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
4668 DONT_TAG_RESULT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004669 } else {
4670 __ Branch(deferred->entry());
4671 }
4672 __ bind(deferred->exit());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004673 __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004674 // Now that we have finished with the object's real address tag it
4675 __ Addu(reg, reg, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004676}
4677
4678
4679void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4680 // TODO(3095996): Get rid of this. For now, we need to make the
4681 // result register contain a valid pointer because it is already
4682 // contained in the register pointer map.
4683 Register reg = ToRegister(instr->result());
4684 __ mov(reg, zero_reg);
4685
4686 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004687 // NumberTagI and NumberTagD use the context from the frame, rather than
4688 // the environment's HContext or HInlinedContext value.
4689 // They only call Runtime::kAllocateHeapNumber.
4690 // The corresponding HChange instructions are added in a phase that does
4691 // not have easy access to the local context.
4692 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4693 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4694 RecordSafepointWithRegisters(
4695 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004696 __ Subu(v0, v0, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004697 __ StoreToSafepointRegisterSlot(v0, reg);
4698}
4699
4700
4701void LCodeGen::DoSmiTag(LSmiTag* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004702 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004703 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004704}
4705
4706
4707void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4708 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004709 Register input = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004710 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004711 if (instr->needs_check()) {
4712 STATIC_ASSERT(kHeapObjectTag == 1);
4713 // If the input is a HeapObject, value of scratch won't be zero.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004714 __ And(scratch, input, Operand(kHeapObjectTag));
4715 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004716 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4717 } else {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004718 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004719 }
4720}
4721
4722
4723void LCodeGen::EmitNumberUntagD(Register input_reg,
4724 DoubleRegister result_reg,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004725 bool can_convert_undefined_to_nan,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004726 bool deoptimize_on_minus_zero,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004727 LEnvironment* env,
4728 NumberUntagDMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004729 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004730 Label convert, load_smi, done;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004731 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004732 // Smi check.
4733 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004734 // Heap number map check.
4735 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4736 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004737 if (can_convert_undefined_to_nan) {
4738 __ Branch(&convert, ne, scratch, Operand(at));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004739 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004740 DeoptimizeIf(ne, env, scratch, Operand(at));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004741 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004742 // Load heap number.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004743 __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4744 if (deoptimize_on_minus_zero) {
4745 __ mfc1(at, result_reg.low());
4746 __ Branch(&done, ne, at, Operand(zero_reg));
4747 __ mfc1(scratch, result_reg.high());
4748 DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask));
4749 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004750 __ Branch(&done);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004751 if (can_convert_undefined_to_nan) {
4752 __ bind(&convert);
4753 // Convert undefined (and hole) to NaN.
4754 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4755 DeoptimizeIf(ne, env, input_reg, Operand(at));
4756 __ LoadRoot(scratch, Heap::kNanValueRootIndex);
4757 __ ldc1(result_reg, FieldMemOperand(scratch, HeapNumber::kValueOffset));
4758 __ Branch(&done);
4759 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004760 } else {
4761 __ SmiUntag(scratch, input_reg);
4762 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004763 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004764 // Smi to double register conversion
4765 __ bind(&load_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004766 // scratch: untagged value of input_reg
4767 __ mtc1(scratch, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004768 __ cvt_d_w(result_reg, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004769 __ bind(&done);
4770}
4771
4772
4773void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004774 Register input_reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004775 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004776 Register scratch2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004777 DoubleRegister double_scratch = double_scratch0();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004778 DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004779
4780 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
4781 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
4782
4783 Label done;
4784
4785 // The input is a tagged HeapObject.
4786 // Heap number map check.
4787 __ lw(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4788 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4789 // This 'at' value and scratch1 map value are used for tests in both clauses
4790 // of the if.
4791
4792 if (instr->truncating()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004793 // Performs a truncating conversion of a floating point number as used by
4794 // the JS bitwise operations.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004795 Label no_heap_number, check_bools, check_false;
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00004796 // Check HeapNumber map.
4797 __ Branch(USE_DELAY_SLOT, &no_heap_number, ne, scratch1, Operand(at));
4798 __ mov(scratch2, input_reg); // In delay slot.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004799 __ TruncateHeapNumberToI(input_reg, scratch2);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004800 __ Branch(&done);
4801
4802 // Check for Oddballs. Undefined/False is converted to zero and True to one
4803 // for truncating conversions.
4804 __ bind(&no_heap_number);
4805 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4806 __ Branch(&check_bools, ne, input_reg, Operand(at));
4807 ASSERT(ToRegister(instr->result()).is(input_reg));
4808 __ Branch(USE_DELAY_SLOT, &done);
4809 __ mov(input_reg, zero_reg); // In delay slot.
4810
4811 __ bind(&check_bools);
4812 __ LoadRoot(at, Heap::kTrueValueRootIndex);
4813 __ Branch(&check_false, ne, scratch2, Operand(at));
4814 __ Branch(USE_DELAY_SLOT, &done);
4815 __ li(input_reg, Operand(1)); // In delay slot.
4816
4817 __ bind(&check_false);
4818 __ LoadRoot(at, Heap::kFalseValueRootIndex);
4819 DeoptimizeIf(ne, instr->environment(), scratch2, Operand(at));
4820 __ Branch(USE_DELAY_SLOT, &done);
4821 __ mov(input_reg, zero_reg); // In delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004822 } else {
4823 // Deoptimize if we don't have a heap number.
4824 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at));
4825
4826 // Load the double value.
4827 __ ldc1(double_scratch,
4828 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4829
4830 Register except_flag = scratch2;
4831 __ EmitFPUTruncate(kRoundToZero,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004832 input_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004833 double_scratch,
4834 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004835 double_scratch2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004836 except_flag,
4837 kCheckForInexactConversion);
4838
4839 // Deopt if the operation did not succeed.
4840 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4841
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004842 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4843 __ Branch(&done, ne, input_reg, Operand(zero_reg));
4844
4845 __ mfc1(scratch1, double_scratch.high());
4846 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4847 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4848 }
4849 }
4850 __ bind(&done);
4851}
4852
4853
4854void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004855 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004856 public:
4857 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4858 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004859 virtual void Generate() V8_OVERRIDE {
4860 codegen()->DoDeferredTaggedToI(instr_);
4861 }
4862 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004863 private:
4864 LTaggedToI* instr_;
4865 };
4866
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004867 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004868 ASSERT(input->IsRegister());
4869 ASSERT(input->Equals(instr->result()));
4870
4871 Register input_reg = ToRegister(input);
4872
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004873 if (instr->hydrogen()->value()->representation().IsSmi()) {
4874 __ SmiUntag(input_reg);
4875 } else {
4876 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004877
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004878 // Let the deferred code handle the HeapObject case.
4879 __ JumpIfNotSmi(input_reg, deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004880
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004881 // Smi to int32 conversion.
4882 __ SmiUntag(input_reg);
4883 __ bind(deferred->exit());
4884 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004885}
4886
4887
4888void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004889 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004890 ASSERT(input->IsRegister());
4891 LOperand* result = instr->result();
4892 ASSERT(result->IsDoubleRegister());
4893
4894 Register input_reg = ToRegister(input);
4895 DoubleRegister result_reg = ToDoubleRegister(result);
4896
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004897 HValue* value = instr->hydrogen()->value();
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004898 NumberUntagDMode mode = value->representation().IsSmi()
4899 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004900
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004901 EmitNumberUntagD(input_reg, result_reg,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004902 instr->hydrogen()->can_convert_undefined_to_nan(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004903 instr->hydrogen()->deoptimize_on_minus_zero(),
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004904 instr->environment(),
4905 mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004906}
4907
4908
4909void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
4910 Register result_reg = ToRegister(instr->result());
4911 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004912 DoubleRegister double_input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004913
4914 if (instr->truncating()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004915 __ TruncateDoubleToI(result_reg, double_input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004916 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004917 Register except_flag = LCodeGen::scratch1();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004918
4919 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004920 result_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004921 double_input,
4922 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004923 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004924 except_flag,
4925 kCheckForInexactConversion);
4926
4927 // Deopt if the operation did not succeed (except_flag != 0).
4928 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004929
4930 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4931 Label done;
4932 __ Branch(&done, ne, result_reg, Operand(zero_reg));
4933 __ mfc1(scratch1, double_input.high());
4934 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4935 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4936 __ bind(&done);
4937 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004938 }
4939}
4940
4941
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004942void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4943 Register result_reg = ToRegister(instr->result());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004944 Register scratch1 = LCodeGen::scratch0();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004945 DoubleRegister double_input = ToDoubleRegister(instr->value());
4946
4947 if (instr->truncating()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004948 __ TruncateDoubleToI(result_reg, double_input);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004949 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004950 Register except_flag = LCodeGen::scratch1();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004951
4952 __ EmitFPUTruncate(kRoundToMinusInf,
4953 result_reg,
4954 double_input,
4955 scratch1,
4956 double_scratch0(),
4957 except_flag,
4958 kCheckForInexactConversion);
4959
4960 // Deopt if the operation did not succeed (except_flag != 0).
4961 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4962
4963 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4964 Label done;
4965 __ Branch(&done, ne, result_reg, Operand(zero_reg));
4966 __ mfc1(scratch1, double_input.high());
4967 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4968 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4969 __ bind(&done);
4970 }
4971 }
4972 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1);
4973 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg));
4974}
4975
4976
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004977void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004978 LOperand* input = instr->value();
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00004979 __ SmiTst(ToRegister(input), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004980 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
4981}
4982
4983
4984void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004985 if (!instr->hydrogen()->value()->IsHeapObject()) {
4986 LOperand* input = instr->value();
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00004987 __ SmiTst(ToRegister(input), at);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004988 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
4989 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004990}
4991
4992
4993void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004994 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004995 Register scratch = scratch0();
4996
4997 __ GetObjectType(input, scratch, scratch);
4998
4999 if (instr->hydrogen()->is_interval_check()) {
5000 InstanceType first;
5001 InstanceType last;
5002 instr->hydrogen()->GetCheckInterval(&first, &last);
5003
5004 // If there is only one type in the interval check for equality.
5005 if (first == last) {
5006 DeoptimizeIf(ne, instr->environment(), scratch, Operand(first));
5007 } else {
5008 DeoptimizeIf(lo, instr->environment(), scratch, Operand(first));
5009 // Omit check for the last type.
5010 if (last != LAST_TYPE) {
5011 DeoptimizeIf(hi, instr->environment(), scratch, Operand(last));
5012 }
5013 }
5014 } else {
5015 uint8_t mask;
5016 uint8_t tag;
5017 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5018
5019 if (IsPowerOf2(mask)) {
5020 ASSERT(tag == 0 || IsPowerOf2(tag));
5021 __ And(at, scratch, mask);
5022 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment(),
5023 at, Operand(zero_reg));
5024 } else {
5025 __ And(scratch, scratch, Operand(mask));
5026 DeoptimizeIf(ne, instr->environment(), scratch, Operand(tag));
5027 }
5028 }
5029}
5030
5031
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005032void LCodeGen::DoCheckValue(LCheckValue* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005033 Register reg = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005034 Handle<HeapObject> object = instr->hydrogen()->object().handle();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005035 AllowDeferredHandleDereference smi_check;
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005036 if (isolate()->heap()->InNewSpace(*object)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005037 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005038 Handle<Cell> cell = isolate()->factory()->NewCell(object);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005039 __ li(at, Operand(Handle<Object>(cell)));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00005040 __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005041 DeoptimizeIf(ne, instr->environment(), reg,
5042 Operand(at));
5043 } else {
5044 DeoptimizeIf(ne, instr->environment(), reg,
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005045 Operand(object));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005046 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005047}
5048
5049
danno@chromium.org59400602013-08-13 17:09:37 +00005050void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5051 {
5052 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
5053 __ push(object);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005054 __ mov(cp, zero_reg);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00005055 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005056 RecordSafepointWithRegisters(
5057 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
danno@chromium.org59400602013-08-13 17:09:37 +00005058 __ StoreToSafepointRegisterSlot(v0, scratch0());
5059 }
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00005060 __ SmiTst(scratch0(), at);
danno@chromium.org59400602013-08-13 17:09:37 +00005061 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005062}
5063
5064
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005065void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005066 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00005067 public:
5068 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
5069 : LDeferredCode(codegen), instr_(instr), object_(object) {
5070 SetExit(check_maps());
5071 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005072 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00005073 codegen()->DoDeferredInstanceMigration(instr_, object_);
5074 }
5075 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005076 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00005077 private:
5078 LCheckMaps* instr_;
5079 Label check_maps_;
5080 Register object_;
5081 };
5082
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005083 if (instr->hydrogen()->CanOmitMapChecks()) return;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005084 Register map_reg = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005085 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005086 ASSERT(input->IsRegister());
5087 Register reg = ToRegister(input);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005088 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
danno@chromium.org59400602013-08-13 17:09:37 +00005089
5090 DeferredCheckMaps* deferred = NULL;
5091 if (instr->hydrogen()->has_migration_target()) {
5092 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
5093 __ bind(deferred->check_maps());
5094 }
5095
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005096 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005097 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005098 for (int i = 0; i < map_set.size() - 1; i++) {
5099 Handle<Map> map = map_set.at(i).handle();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005100 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005101 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005102 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
danno@chromium.org59400602013-08-13 17:09:37 +00005103 // Do the CompareMap() directly within the Branch() and DeoptimizeIf().
5104 if (instr->hydrogen()->has_migration_target()) {
5105 __ Branch(deferred->entry(), ne, map_reg, Operand(map));
5106 } else {
5107 DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map));
5108 }
5109
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005110 __ bind(&success);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005111}
5112
5113
5114void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5115 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
5116 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005117 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005118 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
5119}
5120
5121
5122void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5123 Register unclamped_reg = ToRegister(instr->unclamped());
5124 Register result_reg = ToRegister(instr->result());
5125 __ ClampUint8(result_reg, unclamped_reg);
5126}
5127
5128
5129void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5130 Register scratch = scratch0();
5131 Register input_reg = ToRegister(instr->unclamped());
5132 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005133 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005134 Label is_smi, done, heap_number;
5135
5136 // Both smi and heap number cases are handled.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005137 __ UntagAndJumpIfSmi(scratch, input_reg, &is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005138
5139 // Check for heap number
5140 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
5141 __ Branch(&heap_number, eq, scratch, Operand(factory()->heap_number_map()));
5142
5143 // Check for undefined. Undefined is converted to zero for clamping
5144 // conversions.
5145 DeoptimizeIf(ne, instr->environment(), input_reg,
5146 Operand(factory()->undefined_value()));
5147 __ mov(result_reg, zero_reg);
5148 __ jmp(&done);
5149
5150 // Heap number
5151 __ bind(&heap_number);
5152 __ ldc1(double_scratch0(), FieldMemOperand(input_reg,
5153 HeapNumber::kValueOffset));
5154 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
5155 __ jmp(&done);
5156
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005157 __ bind(&is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005158 __ ClampUint8(result_reg, scratch);
5159
5160 __ bind(&done);
5161}
5162
5163
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005164void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005165 class DeferredAllocate V8_FINAL : public LDeferredCode {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005166 public:
5167 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5168 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005169 virtual void Generate() V8_OVERRIDE {
5170 codegen()->DoDeferredAllocate(instr_);
5171 }
5172 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005173 private:
5174 LAllocate* instr_;
5175 };
5176
5177 DeferredAllocate* deferred =
5178 new(zone()) DeferredAllocate(this, instr);
5179
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005180 Register result = ToRegister(instr->result());
5181 Register scratch = ToRegister(instr->temp1());
5182 Register scratch2 = ToRegister(instr->temp2());
5183
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005184 // Allocate memory for the object.
5185 AllocationFlags flags = TAG_OBJECT;
5186 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5187 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5188 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005189 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5190 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5191 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005192 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005193 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5194 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005195 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005196 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005197 if (instr->size()->IsConstantOperand()) {
5198 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005199 __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005200 } else {
5201 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005202 __ Allocate(size,
5203 result,
5204 scratch,
5205 scratch2,
5206 deferred->entry(),
5207 flags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005208 }
5209
5210 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005211
5212 if (instr->hydrogen()->MustPrefillWithFiller()) {
5213 if (instr->size()->IsConstantOperand()) {
5214 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5215 __ li(scratch, Operand(size));
5216 } else {
5217 scratch = ToRegister(instr->size());
5218 }
5219 __ Subu(scratch, scratch, Operand(kPointerSize));
5220 __ Subu(result, result, Operand(kHeapObjectTag));
5221 Label loop;
5222 __ bind(&loop);
5223 __ li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
5224 __ Addu(at, result, Operand(scratch));
5225 __ sw(scratch2, MemOperand(at));
5226 __ Subu(scratch, scratch, Operand(kPointerSize));
5227 __ Branch(&loop, ge, scratch, Operand(zero_reg));
5228 __ Addu(result, result, Operand(kHeapObjectTag));
5229 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005230}
5231
5232
5233void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005234 Register result = ToRegister(instr->result());
5235
5236 // TODO(3095996): Get rid of this. For now, we need to make the
5237 // result register contain a valid pointer because it is already
5238 // contained in the register pointer map.
5239 __ mov(result, zero_reg);
5240
5241 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005242 if (instr->size()->IsRegister()) {
5243 Register size = ToRegister(instr->size());
5244 ASSERT(!size.is(result));
5245 __ SmiTag(size);
5246 __ push(size);
5247 } else {
5248 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5249 __ Push(Smi::FromInt(size));
5250 }
5251
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005252 int flags = AllocateDoubleAlignFlag::encode(
5253 instr->hydrogen()->MustAllocateDoubleAligned());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005254 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5255 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5256 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005257 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005258 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5259 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005260 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005261 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005262 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005263 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005264 __ Push(Smi::FromInt(flags));
5265
5266 CallRuntimeFromDeferred(
5267 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005268 __ StoreToSafepointRegisterSlot(v0, result);
5269}
5270
5271
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005272void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005273 ASSERT(ToRegister(instr->value()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005274 ASSERT(ToRegister(instr->result()).is(v0));
5275 __ push(a0);
5276 CallRuntime(Runtime::kToFastProperties, 1, instr);
5277}
5278
5279
5280void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005281 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005282 Label materialized;
5283 // Registers will be used as follows:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005284 // t3 = literals array.
5285 // a1 = regexp literal.
5286 // a0 = regexp literal clone.
5287 // a2 and t0-t2 are used as temporaries.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005288 int literal_offset =
5289 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005290 __ li(t3, instr->hydrogen()->literals());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005291 __ lw(a1, FieldMemOperand(t3, literal_offset));
5292 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5293 __ Branch(&materialized, ne, a1, Operand(at));
5294
5295 // Create regexp literal using runtime function
5296 // Result will be in v0.
5297 __ li(t2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
5298 __ li(t1, Operand(instr->hydrogen()->pattern()));
5299 __ li(t0, Operand(instr->hydrogen()->flags()));
5300 __ Push(t3, t2, t1, t0);
5301 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5302 __ mov(a1, v0);
5303
5304 __ bind(&materialized);
5305 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5306 Label allocated, runtime_allocate;
5307
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005308 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005309 __ jmp(&allocated);
5310
5311 __ bind(&runtime_allocate);
5312 __ li(a0, Operand(Smi::FromInt(size)));
5313 __ Push(a1, a0);
5314 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5315 __ pop(a1);
5316
5317 __ bind(&allocated);
5318 // Copy the content into the newly allocated memory.
5319 // (Unroll copy loop once for better throughput).
5320 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5321 __ lw(a3, FieldMemOperand(a1, i));
5322 __ lw(a2, FieldMemOperand(a1, i + kPointerSize));
5323 __ sw(a3, FieldMemOperand(v0, i));
5324 __ sw(a2, FieldMemOperand(v0, i + kPointerSize));
5325 }
5326 if ((size % (2 * kPointerSize)) != 0) {
5327 __ lw(a3, FieldMemOperand(a1, size - kPointerSize));
5328 __ sw(a3, FieldMemOperand(v0, size - kPointerSize));
5329 }
5330}
5331
5332
5333void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005334 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005335 // Use the fast case closure allocation code that allocates in new
5336 // space for nested functions that don't need literals cloning.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005337 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005338 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5339 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5340 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005341 __ li(a2, Operand(instr->hydrogen()->shared_info()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005342 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005343 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005344 __ li(a2, Operand(instr->hydrogen()->shared_info()));
5345 __ li(a1, Operand(pretenure ? factory()->true_value()
5346 : factory()->false_value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005347 __ Push(cp, a2, a1);
5348 CallRuntime(Runtime::kNewClosure, 3, instr);
5349 }
5350}
5351
5352
5353void LCodeGen::DoTypeof(LTypeof* instr) {
5354 ASSERT(ToRegister(instr->result()).is(v0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005355 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005356 __ push(input);
5357 CallRuntime(Runtime::kTypeof, 1, instr);
5358}
5359
5360
5361void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005362 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005363
5364 Register cmp1 = no_reg;
5365 Operand cmp2 = Operand(no_reg);
5366
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005367 Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_),
5368 instr->FalseLabel(chunk_),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005369 input,
5370 instr->type_literal(),
5371 cmp1,
5372 cmp2);
5373
5374 ASSERT(cmp1.is_valid());
5375 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid());
5376
5377 if (final_branch_condition != kNoCondition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005378 EmitBranch(instr, final_branch_condition, cmp1, cmp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005379 }
5380}
5381
5382
5383Condition LCodeGen::EmitTypeofIs(Label* true_label,
5384 Label* false_label,
5385 Register input,
5386 Handle<String> type_name,
5387 Register& cmp1,
5388 Operand& cmp2) {
5389 // This function utilizes the delay slot heavily. This is used to load
5390 // values that are always usable without depending on the type of the input
5391 // register.
5392 Condition final_branch_condition = kNoCondition;
5393 Register scratch = scratch0();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005394 if (type_name->Equals(heap()->number_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005395 __ JumpIfSmi(input, true_label);
5396 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5397 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
5398 cmp1 = input;
5399 cmp2 = Operand(at);
5400 final_branch_condition = eq;
5401
ulan@chromium.org750145a2013-03-07 15:14:13 +00005402 } else if (type_name->Equals(heap()->string_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005403 __ JumpIfSmi(input, false_label);
5404 __ GetObjectType(input, input, scratch);
5405 __ Branch(USE_DELAY_SLOT, false_label,
5406 ge, scratch, Operand(FIRST_NONSTRING_TYPE));
5407 // input is an object so we can load the BitFieldOffset even if we take the
5408 // other branch.
5409 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5410 __ And(at, at, 1 << Map::kIsUndetectable);
5411 cmp1 = at;
5412 cmp2 = Operand(zero_reg);
5413 final_branch_condition = eq;
5414
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005415 } else if (type_name->Equals(heap()->symbol_string())) {
5416 __ JumpIfSmi(input, false_label);
5417 __ GetObjectType(input, input, scratch);
5418 cmp1 = scratch;
5419 cmp2 = Operand(SYMBOL_TYPE);
5420 final_branch_condition = eq;
5421
ulan@chromium.org750145a2013-03-07 15:14:13 +00005422 } else if (type_name->Equals(heap()->boolean_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005423 __ LoadRoot(at, Heap::kTrueValueRootIndex);
5424 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5425 __ LoadRoot(at, Heap::kFalseValueRootIndex);
5426 cmp1 = at;
5427 cmp2 = Operand(input);
5428 final_branch_condition = eq;
5429
ulan@chromium.org750145a2013-03-07 15:14:13 +00005430 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005431 __ LoadRoot(at, Heap::kNullValueRootIndex);
5432 cmp1 = at;
5433 cmp2 = Operand(input);
5434 final_branch_condition = eq;
5435
ulan@chromium.org750145a2013-03-07 15:14:13 +00005436 } else if (type_name->Equals(heap()->undefined_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005437 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5438 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5439 // The first instruction of JumpIfSmi is an And - it is safe in the delay
5440 // slot.
5441 __ JumpIfSmi(input, false_label);
5442 // Check for undetectable objects => true.
5443 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5444 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5445 __ And(at, at, 1 << Map::kIsUndetectable);
5446 cmp1 = at;
5447 cmp2 = Operand(zero_reg);
5448 final_branch_condition = ne;
5449
ulan@chromium.org750145a2013-03-07 15:14:13 +00005450 } else if (type_name->Equals(heap()->function_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005451 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5452 __ JumpIfSmi(input, false_label);
5453 __ GetObjectType(input, scratch, input);
5454 __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE));
5455 cmp1 = input;
5456 cmp2 = Operand(JS_FUNCTION_PROXY_TYPE);
5457 final_branch_condition = eq;
5458
ulan@chromium.org750145a2013-03-07 15:14:13 +00005459 } else if (type_name->Equals(heap()->object_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005460 __ JumpIfSmi(input, false_label);
5461 if (!FLAG_harmony_typeof) {
5462 __ LoadRoot(at, Heap::kNullValueRootIndex);
5463 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5464 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005465 Register map = input;
5466 __ GetObjectType(input, map, scratch);
5467 __ Branch(false_label,
5468 lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005469 __ Branch(USE_DELAY_SLOT, false_label,
5470 gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005471 // map is still valid, so the BitField can be loaded in delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005472 // Check for undetectable objects => false.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005473 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005474 __ And(at, at, 1 << Map::kIsUndetectable);
5475 cmp1 = at;
5476 cmp2 = Operand(zero_reg);
5477 final_branch_condition = eq;
5478
5479 } else {
5480 cmp1 = at;
5481 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion.
5482 __ Branch(false_label);
5483 }
5484
5485 return final_branch_condition;
5486}
5487
5488
5489void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005490 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005491
5492 EmitIsConstructCall(temp1, scratch0());
5493
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005494 EmitBranch(instr, eq, temp1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005495 Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
5496}
5497
5498
5499void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
5500 ASSERT(!temp1.is(temp2));
5501 // Get the frame pointer for the calling frame.
5502 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5503
5504 // Skip the arguments adaptor frame if it exists.
5505 Label check_frame_marker;
5506 __ lw(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
5507 __ Branch(&check_frame_marker, ne, temp2,
5508 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
5509 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
5510
5511 // Check the marker in the calling frame.
5512 __ bind(&check_frame_marker);
5513 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
5514}
5515
5516
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005517void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00005518 if (!info()->IsStub()) {
5519 // Ensure that we have enough space after the previous lazy-bailout
5520 // instruction for patching the code here.
5521 int current_pc = masm()->pc_offset();
5522 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5523 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
5524 ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
5525 while (padding_size > 0) {
5526 __ nop();
5527 padding_size -= Assembler::kInstrSize;
5528 }
erikcorry0ad885c2011-11-21 13:51:57 +00005529 }
5530 }
machenbach@chromium.org5c88bc32014-01-17 08:10:36 +00005531 last_lazy_deopt_pc_ = masm()->pc_offset();
erikcorry0ad885c2011-11-21 13:51:57 +00005532}
5533
5534
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005535void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005536 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
erikcorry0ad885c2011-11-21 13:51:57 +00005537 ASSERT(instr->HasEnvironment());
5538 LEnvironment* env = instr->environment();
5539 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5540 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005541}
5542
5543
5544void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005545 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5546 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5547 // needed return address), even though the implementation of LAZY and EAGER is
5548 // now identical. When LAZY is eventually completely folded into EAGER, remove
5549 // the special case below.
5550 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5551 type = Deoptimizer::LAZY;
palfia@homejinni.com04109732013-05-15 09:50:32 +00005552 }
danno@chromium.org59400602013-08-13 17:09:37 +00005553
5554 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005555 DeoptimizeIf(al, instr->environment(), type, zero_reg, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005556}
5557
5558
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005559void LCodeGen::DoDummy(LDummy* instr) {
5560 // Nothing to see here, move on!
5561}
5562
5563
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005564void LCodeGen::DoDummyUse(LDummyUse* instr) {
5565 // Nothing to see here, move on!
5566}
5567
5568
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005569void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005570 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005571 LoadContextFromDeferred(instr->context());
erikcorry0ad885c2011-11-21 13:51:57 +00005572 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5573 RecordSafepointWithLazyDeopt(
5574 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5575 ASSERT(instr->HasEnvironment());
5576 LEnvironment* env = instr->environment();
5577 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005578}
5579
5580
5581void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005582 class DeferredStackCheck V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005583 public:
5584 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5585 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005586 virtual void Generate() V8_OVERRIDE {
5587 codegen()->DoDeferredStackCheck(instr_);
5588 }
5589 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005590 private:
5591 LStackCheck* instr_;
5592 };
5593
erikcorry0ad885c2011-11-21 13:51:57 +00005594 ASSERT(instr->HasEnvironment());
5595 LEnvironment* env = instr->environment();
5596 // There is no LLazyBailout instruction for stack-checks. We have to
5597 // prepare for lazy deoptimization explicitly here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005598 if (instr->hydrogen()->is_function_entry()) {
5599 // Perform stack overflow check.
5600 Label done;
5601 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5602 __ Branch(&done, hs, sp, Operand(at));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005603 ASSERT(instr->context()->IsRegister());
5604 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005605 CallCode(isolate()->builtins()->StackCheck(),
5606 RelocInfo::CODE_TARGET,
5607 instr);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005608 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005609 __ bind(&done);
erikcorry0ad885c2011-11-21 13:51:57 +00005610 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5611 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005612 } else {
5613 ASSERT(instr->hydrogen()->is_backwards_branch());
5614 // Perform stack overflow check if this goto needs it before jumping.
5615 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005616 new(zone()) DeferredStackCheck(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005617 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5618 __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005619 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005620 __ bind(instr->done_label());
5621 deferred_stack_check->SetExit(instr->done_label());
erikcorry0ad885c2011-11-21 13:51:57 +00005622 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5623 // Don't record a deoptimization index for the safepoint here.
5624 // This will be done explicitly when emitting call and the safepoint in
5625 // the deferred code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005626 }
5627}
5628
5629
5630void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5631 // This is a pseudo-instruction that ensures that the environment here is
5632 // properly registered for deoptimization and records the assembler's PC
5633 // offset.
5634 LEnvironment* environment = instr->environment();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005635
5636 // If the environment were already registered, we would have no way of
5637 // backpatching it with the spill slot operands.
5638 ASSERT(!environment->HasBeenRegistered());
erikcorry0ad885c2011-11-21 13:51:57 +00005639 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005640
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005641 GenerateOsrPrologue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005642}
5643
5644
ulan@chromium.org812308e2012-02-29 15:58:45 +00005645void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5646 Register result = ToRegister(instr->result());
5647 Register object = ToRegister(instr->object());
5648 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5649 DeoptimizeIf(eq, instr->environment(), object, Operand(at));
5650
5651 Register null_value = t1;
5652 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5653 DeoptimizeIf(eq, instr->environment(), object, Operand(null_value));
5654
5655 __ And(at, object, kSmiTagMask);
5656 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5657
5658 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5659 __ GetObjectType(object, a1, a1);
5660 DeoptimizeIf(le, instr->environment(), a1, Operand(LAST_JS_PROXY_TYPE));
5661
5662 Label use_cache, call_runtime;
5663 ASSERT(object.is(a0));
5664 __ CheckEnumCache(null_value, &call_runtime);
5665
5666 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
5667 __ Branch(&use_cache);
5668
5669 // Get the set of properties to enumerate.
5670 __ bind(&call_runtime);
5671 __ push(object);
5672 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5673
5674 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
5675 ASSERT(result.is(v0));
5676 __ LoadRoot(at, Heap::kMetaMapRootIndex);
5677 DeoptimizeIf(ne, instr->environment(), a1, Operand(at));
5678 __ bind(&use_cache);
5679}
5680
5681
5682void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5683 Register map = ToRegister(instr->map());
5684 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005685 Label load_cache, done;
5686 __ EnumLength(result, map);
5687 __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0)));
5688 __ li(result, Operand(isolate()->factory()->empty_fixed_array()));
5689 __ jmp(&done);
5690
5691 __ bind(&load_cache);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005692 __ LoadInstanceDescriptors(map, result);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005693 __ lw(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005694 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +00005695 __ lw(result,
5696 FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
5697 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005698
5699 __ bind(&done);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005700}
5701
5702
5703void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5704 Register object = ToRegister(instr->value());
5705 Register map = ToRegister(instr->map());
5706 __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
5707 DeoptimizeIf(ne, instr->environment(), map, Operand(scratch0()));
5708}
5709
5710
5711void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5712 Register object = ToRegister(instr->object());
5713 Register index = ToRegister(instr->index());
5714 Register result = ToRegister(instr->result());
5715 Register scratch = scratch0();
5716
5717 Label out_of_object, done;
5718 __ Branch(USE_DELAY_SLOT, &out_of_object, lt, index, Operand(zero_reg));
5719 __ sll(scratch, index, kPointerSizeLog2 - kSmiTagSize); // In delay slot.
5720
5721 STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
5722 __ Addu(scratch, object, scratch);
5723 __ lw(result, FieldMemOperand(scratch, JSObject::kHeaderSize));
5724
5725 __ Branch(&done);
5726
5727 __ bind(&out_of_object);
5728 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
5729 // Index is equal to negated out of object property index plus 1.
5730 __ Subu(scratch, result, scratch);
5731 __ lw(result, FieldMemOperand(scratch,
5732 FixedArray::kHeaderSize - kPointerSize));
5733 __ bind(&done);
5734}
5735
5736
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005737#undef __
5738
5739} } // namespace v8::internal