blob: d54e5ec1518b34c63fe9159f1d3f033b148bf6f8 [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));
182 __ push(a0);
183 __ push(a1);
184 __ Addu(a0, sp, Operand(slots * kPointerSize));
185 __ li(a1, Operand(kSlotsZapValue));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000186 Label loop;
187 __ bind(&loop);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000188 __ Subu(a0, a0, Operand(kPointerSize));
189 __ sw(a1, MemOperand(a0, 2 * kPointerSize));
190 __ Branch(&loop, ne, a0, Operand(sp));
191 __ pop(a1);
192 __ pop(a0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000193 } else {
194 __ Subu(sp, sp, Operand(slots * kPointerSize));
195 }
196 }
197
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000198 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000199 SaveCallerDoubles();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000200 }
201
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000202 // Possibly allocate a local context.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000203 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000204 if (heap_slots > 0) {
205 Comment(";;; Allocate local context");
206 // Argument to NewContext is the function, which is in a1.
207 __ push(a1);
208 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
209 FastNewContextStub stub(heap_slots);
210 __ CallStub(&stub);
211 } else {
212 __ CallRuntime(Runtime::kNewFunctionContext, 1);
213 }
erikcorry0ad885c2011-11-21 13:51:57 +0000214 RecordSafepoint(Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000215 // Context is returned in both v0 and cp. It replaces the context
216 // passed to us. It's saved in the stack and kept live in cp.
217 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
218 // Copy any necessary parameters into the context.
219 int num_parameters = scope()->num_parameters();
220 for (int i = 0; i < num_parameters; i++) {
221 Variable* var = scope()->parameter(i);
222 if (var->IsContextSlot()) {
223 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
224 (num_parameters - 1 - i) * kPointerSize;
225 // Load parameter from stack.
226 __ lw(a0, MemOperand(fp, parameter_offset));
227 // Store it in the context.
228 MemOperand target = ContextOperand(cp, var->index());
229 __ sw(a0, target);
230 // Update the write barrier. This clobbers a3 and a0.
231 __ RecordWriteContextSlot(
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000232 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000233 }
234 }
235 Comment(";;; End allocate local context");
236 }
237
238 // Trace the call.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000239 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000240 // We have not executed any compiled code yet, so cp still holds the
241 // incoming context.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000242 __ CallRuntime(Runtime::kTraceEnter, 0);
243 }
244 return !is_aborted();
245}
246
247
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000248void LCodeGen::GenerateOsrPrologue() {
249 // Generate the OSR entry prologue at the first unknown OSR value, or if there
250 // are none, at the OSR entrypoint instruction.
251 if (osr_pc_offset_ >= 0) return;
252
253 osr_pc_offset_ = masm()->pc_offset();
254
255 // Adjust the frame size, subsuming the unoptimized frame into the
256 // optimized frame.
257 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
258 ASSERT(slots >= 0);
259 __ Subu(sp, sp, Operand(slots * kPointerSize));
260}
261
262
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000263bool LCodeGen::GenerateDeferredCode() {
264 ASSERT(is_generating());
265 if (deferred_.length() > 0) {
266 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
267 LDeferredCode* code = deferred_[i];
danno@chromium.org59400602013-08-13 17:09:37 +0000268
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000269 HValue* value =
270 instructions_->at(code->instruction_index())->hydrogen_value();
271 RecordAndWritePosition(value->position());
danno@chromium.org59400602013-08-13 17:09:37 +0000272
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000273 Comment(";;; <@%d,#%d> "
274 "-------------------- Deferred %s --------------------",
275 code->instruction_index(),
276 code->instr()->hydrogen_value()->id(),
277 code->instr()->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000278 __ bind(code->entry());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000279 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000280 Comment(";;; Build frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000281 ASSERT(!frame_is_built_);
282 ASSERT(info()->IsStub());
283 frame_is_built_ = true;
284 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
285 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
286 __ push(scratch0());
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000287 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000288 Comment(";;; Deferred code");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000289 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000290 code->Generate();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000291 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000292 Comment(";;; Destroy frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000293 ASSERT(frame_is_built_);
294 __ pop(at);
295 __ MultiPop(cp.bit() | fp.bit() | ra.bit());
296 frame_is_built_ = false;
297 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000298 __ jmp(code->exit());
299 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000300 }
301 // Deferred code is the last part of the instruction sequence. Mark
302 // the generated code as done unless we bailed out.
303 if (!is_aborted()) status_ = DONE;
304 return !is_aborted();
305}
306
307
308bool LCodeGen::GenerateDeoptJumpTable() {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000309 if (deopt_jump_table_.length() > 0) {
310 Comment(";;; -------------------- Jump table --------------------");
311 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000312 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000313 Label table_start;
314 __ bind(&table_start);
danno@chromium.org169691d2013-07-15 08:01:13 +0000315 Label needs_frame;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000316 for (int i = 0; i < deopt_jump_table_.length(); i++) {
317 __ bind(&deopt_jump_table_[i].label);
318 Address entry = deopt_jump_table_[i].address;
palfia@homejinni.com04109732013-05-15 09:50:32 +0000319 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000320 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000321 if (id == Deoptimizer::kNotDeoptimizationEntry) {
322 Comment(";;; jump table entry %d.", i);
323 } else {
324 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
325 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000326 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
327 if (deopt_jump_table_[i].needs_frame) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000328 ASSERT(!info()->saves_caller_doubles());
danno@chromium.org169691d2013-07-15 08:01:13 +0000329 if (needs_frame.is_bound()) {
330 __ Branch(&needs_frame);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000331 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000332 __ bind(&needs_frame);
333 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
334 // This variant of deopt can only be used with stubs. Since we don't
335 // have a function pointer to install in the stack frame that we're
336 // building, install a special marker there instead.
337 ASSERT(info()->IsStub());
338 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
339 __ push(scratch0());
machenbach@chromium.org7ff76072013-11-21 09:47:43 +0000340 __ Addu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
danno@chromium.org169691d2013-07-15 08:01:13 +0000341 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000342 }
343 } else {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000344 if (info()->saves_caller_doubles()) {
345 ASSERT(info()->IsStub());
346 RestoreCallerDoubles();
347 }
danno@chromium.org169691d2013-07-15 08:01:13 +0000348 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000349 }
350 }
351 __ RecordComment("]");
352
353 // The deoptimization jump table is the last part of the instruction
354 // sequence. Mark the generated code as done unless we bailed out.
355 if (!is_aborted()) status_ = DONE;
356 return !is_aborted();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000357}
358
359
360bool LCodeGen::GenerateSafepointTable() {
361 ASSERT(is_done());
362 safepoints_.Emit(masm(), GetStackSlotCount());
363 return !is_aborted();
364}
365
366
367Register LCodeGen::ToRegister(int index) const {
368 return Register::FromAllocationIndex(index);
369}
370
371
372DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
373 return DoubleRegister::FromAllocationIndex(index);
374}
375
376
377Register LCodeGen::ToRegister(LOperand* op) const {
378 ASSERT(op->IsRegister());
379 return ToRegister(op->index());
380}
381
382
383Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
384 if (op->IsRegister()) {
385 return ToRegister(op->index());
386 } else if (op->IsConstantOperand()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000387 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000388 HConstant* constant = chunk_->LookupConstant(const_op);
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000389 Handle<Object> literal = constant->handle(isolate());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000390 Representation r = chunk_->LookupLiteralRepresentation(const_op);
391 if (r.IsInteger32()) {
392 ASSERT(literal->IsNumber());
393 __ li(scratch, Operand(static_cast<int32_t>(literal->Number())));
palfia@homejinni.com09b34542013-08-01 08:07:42 +0000394 } else if (r.IsSmi()) {
395 ASSERT(constant->HasSmiValue());
396 __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value())));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000397 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000398 Abort(kEmitLoadRegisterUnsupportedDoubleImmediate);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000399 } else {
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000400 ASSERT(r.IsSmiOrTagged());
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000401 __ li(scratch, literal);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000402 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000403 return scratch;
404 } else if (op->IsStackSlot() || op->IsArgument()) {
405 __ lw(scratch, ToMemOperand(op));
406 return scratch;
407 }
408 UNREACHABLE();
409 return scratch;
410}
411
412
413DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
414 ASSERT(op->IsDoubleRegister());
415 return ToDoubleRegister(op->index());
416}
417
418
419DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
420 FloatRegister flt_scratch,
421 DoubleRegister dbl_scratch) {
422 if (op->IsDoubleRegister()) {
423 return ToDoubleRegister(op->index());
424 } else if (op->IsConstantOperand()) {
425 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000426 HConstant* constant = chunk_->LookupConstant(const_op);
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000427 Handle<Object> literal = constant->handle(isolate());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000428 Representation r = chunk_->LookupLiteralRepresentation(const_op);
429 if (r.IsInteger32()) {
430 ASSERT(literal->IsNumber());
431 __ li(at, Operand(static_cast<int32_t>(literal->Number())));
432 __ mtc1(at, flt_scratch);
433 __ cvt_d_w(dbl_scratch, flt_scratch);
434 return dbl_scratch;
435 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000436 Abort(kUnsupportedDoubleImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000437 } else if (r.IsTagged()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000438 Abort(kUnsupportedTaggedImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000439 }
440 } else if (op->IsStackSlot() || op->IsArgument()) {
441 MemOperand mem_op = ToMemOperand(op);
442 __ ldc1(dbl_scratch, mem_op);
443 return dbl_scratch;
444 }
445 UNREACHABLE();
446 return dbl_scratch;
447}
448
449
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000450Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000451 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000452 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000453 return constant->handle(isolate());
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000454}
455
456
457bool LCodeGen::IsInteger32(LConstantOperand* op) const {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000458 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000459}
460
461
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000462bool LCodeGen::IsSmi(LConstantOperand* op) const {
463 return chunk_->LookupLiteralRepresentation(op).IsSmi();
464}
465
466
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000467int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
468 return ToRepresentation(op, Representation::Integer32());
469}
470
471
472int32_t LCodeGen::ToRepresentation(LConstantOperand* op,
473 const Representation& r) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000474 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000475 int32_t value = constant->Integer32Value();
476 if (r.IsInteger32()) return value;
477 ASSERT(r.IsSmiOrTagged());
478 return reinterpret_cast<int32_t>(Smi::FromInt(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000479}
480
481
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000482Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
483 HConstant* constant = chunk_->LookupConstant(op);
484 return Smi::FromInt(constant->Integer32Value());
485}
486
487
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000488double LCodeGen::ToDouble(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000489 HConstant* constant = chunk_->LookupConstant(op);
490 ASSERT(constant->HasDoubleValue());
491 return constant->DoubleValue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000492}
493
494
495Operand LCodeGen::ToOperand(LOperand* op) {
496 if (op->IsConstantOperand()) {
497 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000498 HConstant* constant = chunk()->LookupConstant(const_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000499 Representation r = chunk_->LookupLiteralRepresentation(const_op);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000500 if (r.IsSmi()) {
501 ASSERT(constant->HasSmiValue());
502 return Operand(Smi::FromInt(constant->Integer32Value()));
503 } else if (r.IsInteger32()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000504 ASSERT(constant->HasInteger32Value());
505 return Operand(constant->Integer32Value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000506 } else if (r.IsDouble()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000507 Abort(kToOperandUnsupportedDoubleImmediate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000508 }
509 ASSERT(r.IsTagged());
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000510 return Operand(constant->handle(isolate()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000511 } else if (op->IsRegister()) {
512 return Operand(ToRegister(op));
513 } else if (op->IsDoubleRegister()) {
danno@chromium.org59400602013-08-13 17:09:37 +0000514 Abort(kToOperandIsDoubleRegisterUnimplemented);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000515 return Operand(0);
516 }
517 // Stack slots not implemented, use ToMemOperand instead.
518 UNREACHABLE();
519 return Operand(0);
520}
521
522
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000523static int ArgumentsOffsetWithoutFrame(int index) {
524 ASSERT(index < 0);
525 return -(index + 1) * kPointerSize;
526}
527
528
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000529MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
530 ASSERT(!op->IsRegister());
531 ASSERT(!op->IsDoubleRegister());
532 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000533 if (NeedsEagerFrame()) {
534 return MemOperand(fp, StackSlotOffset(op->index()));
535 } else {
536 // Retrieve parameter without eager stack-frame relative to the
537 // stack-pointer.
538 return MemOperand(sp, ArgumentsOffsetWithoutFrame(op->index()));
539 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000540}
541
542
543MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
544 ASSERT(op->IsDoubleStackSlot());
machenbach@chromium.orgea468882013-11-18 08:53:19 +0000545 if (NeedsEagerFrame()) {
546 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
547 } else {
548 // Retrieve parameter without eager stack-frame relative to the
549 // stack-pointer.
550 return MemOperand(
551 sp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize);
552 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000553}
554
555
556void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000557 Translation* translation) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000558 if (environment == NULL) return;
559
560 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000561 int translation_size = environment->translation_size();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000562 // The output frame height does not include the parameters.
563 int height = translation_size - environment->parameter_count();
564
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000565 WriteTranslation(environment->outer(), translation);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000566 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000567 !info()->closure().is_identical_to(environment->closure());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000568 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000569 ? DefineDeoptimizationLiteral(environment->closure())
570 : Translation::kSelfLiteralId;
571
ulan@chromium.org812308e2012-02-29 15:58:45 +0000572 switch (environment->frame_type()) {
573 case JS_FUNCTION:
574 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
575 break;
576 case JS_CONSTRUCT:
577 translation->BeginConstructStubFrame(closure_id, translation_size);
578 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000579 case JS_GETTER:
580 ASSERT(translation_size == 1);
581 ASSERT(height == 0);
582 translation->BeginGetterStubFrame(closure_id);
583 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000584 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000585 ASSERT(translation_size == 2);
586 ASSERT(height == 0);
587 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000588 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000589 case STUB:
590 translation->BeginCompiledStubFrame();
591 break;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000592 case ARGUMENTS_ADAPTOR:
593 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
594 break;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000595 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000596
danno@chromium.org59400602013-08-13 17:09:37 +0000597 int object_index = 0;
598 int dematerialized_index = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000599 for (int i = 0; i < translation_size; ++i) {
600 LOperand* value = environment->values()->at(i);
danno@chromium.org59400602013-08-13 17:09:37 +0000601 AddToTranslation(environment,
602 translation,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000603 value,
604 environment->HasTaggedValueAt(i),
danno@chromium.org59400602013-08-13 17:09:37 +0000605 environment->HasUint32ValueAt(i),
606 &object_index,
607 &dematerialized_index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000608 }
609}
610
611
danno@chromium.org59400602013-08-13 17:09:37 +0000612void LCodeGen::AddToTranslation(LEnvironment* environment,
613 Translation* translation,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614 LOperand* op,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000615 bool is_tagged,
danno@chromium.org59400602013-08-13 17:09:37 +0000616 bool is_uint32,
617 int* object_index_pointer,
618 int* dematerialized_index_pointer) {
619 if (op == LEnvironment::materialization_marker()) {
620 int object_index = (*object_index_pointer)++;
621 if (environment->ObjectIsDuplicateAt(object_index)) {
622 int dupe_of = environment->ObjectDuplicateOfAt(object_index);
623 translation->DuplicateObject(dupe_of);
624 return;
625 }
626 int object_length = environment->ObjectLengthAt(object_index);
627 if (environment->ObjectIsArgumentsAt(object_index)) {
628 translation->BeginArgumentsObject(object_length);
629 } else {
630 translation->BeginCapturedObject(object_length);
631 }
632 int dematerialized_index = *dematerialized_index_pointer;
633 int env_offset = environment->translation_size() + dematerialized_index;
634 *dematerialized_index_pointer += object_length;
635 for (int i = 0; i < object_length; ++i) {
636 LOperand* value = environment->values()->at(env_offset + i);
637 AddToTranslation(environment,
638 translation,
639 value,
640 environment->HasTaggedValueAt(env_offset + i),
641 environment->HasUint32ValueAt(env_offset + i),
642 object_index_pointer,
643 dematerialized_index_pointer);
644 }
645 return;
646 }
647
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000648 if (op->IsStackSlot()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000649 if (is_tagged) {
650 translation->StoreStackSlot(op->index());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000651 } else if (is_uint32) {
652 translation->StoreUint32StackSlot(op->index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000653 } else {
654 translation->StoreInt32StackSlot(op->index());
655 }
656 } else if (op->IsDoubleStackSlot()) {
657 translation->StoreDoubleStackSlot(op->index());
658 } else if (op->IsArgument()) {
659 ASSERT(is_tagged);
660 int src_index = GetStackSlotCount() + op->index();
661 translation->StoreStackSlot(src_index);
662 } else if (op->IsRegister()) {
663 Register reg = ToRegister(op);
664 if (is_tagged) {
665 translation->StoreRegister(reg);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000666 } else if (is_uint32) {
667 translation->StoreUint32Register(reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000668 } else {
669 translation->StoreInt32Register(reg);
670 }
671 } else if (op->IsDoubleRegister()) {
672 DoubleRegister reg = ToDoubleRegister(op);
673 translation->StoreDoubleRegister(reg);
674 } else if (op->IsConstantOperand()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000675 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +0000676 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000677 translation->StoreLiteral(src_index);
678 } else {
679 UNREACHABLE();
680 }
681}
682
683
684void LCodeGen::CallCode(Handle<Code> code,
685 RelocInfo::Mode mode,
686 LInstruction* instr) {
687 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
688}
689
690
691void LCodeGen::CallCodeGeneric(Handle<Code> code,
692 RelocInfo::Mode mode,
693 LInstruction* instr,
694 SafepointMode safepoint_mode) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000695 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000696 ASSERT(instr != NULL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 __ Call(code, mode);
erikcorry0ad885c2011-11-21 13:51:57 +0000698 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000699}
700
701
702void LCodeGen::CallRuntime(const Runtime::Function* function,
703 int num_arguments,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000704 LInstruction* instr,
705 SaveFPRegsMode save_doubles) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000706 ASSERT(instr != NULL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000707
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000708 __ CallRuntime(function, num_arguments, save_doubles);
709
erikcorry0ad885c2011-11-21 13:51:57 +0000710 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000711}
712
713
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000714void LCodeGen::LoadContextFromDeferred(LOperand* context) {
715 if (context->IsRegister()) {
716 __ Move(cp, ToRegister(context));
717 } else if (context->IsStackSlot()) {
718 __ lw(cp, ToMemOperand(context));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +0000719 } else if (context->IsConstantOperand()) {
720 HConstant* constant =
721 chunk_->LookupConstant(LConstantOperand::cast(context));
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000722 __ li(cp, Handle<Object>::cast(constant->handle(isolate())));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000723 } else {
724 UNREACHABLE();
725 }
726}
727
728
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000729void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
730 int argc,
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000731 LInstruction* instr,
732 LOperand* context) {
733 LoadContextFromDeferred(context);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000734 __ CallRuntimeSaveDoubles(id);
735 RecordSafepointWithRegisters(
erikcorry0ad885c2011-11-21 13:51:57 +0000736 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000737}
738
739
erikcorry0ad885c2011-11-21 13:51:57 +0000740void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
741 Safepoint::DeoptMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000742 if (!environment->HasBeenRegistered()) {
743 // Physical stack frame layout:
744 // -x ............. -4 0 ..................................... y
745 // [incoming arguments] [spill slots] [pushed outgoing arguments]
746
747 // Layout of the environment:
748 // 0 ..................................................... size-1
749 // [parameters] [locals] [expression stack including arguments]
750
751 // Layout of the translation:
752 // 0 ........................................................ size - 1 + 4
753 // [expression stack including arguments] [locals] [4 words] [parameters]
754 // |>------------ translation_size ------------<|
755
756 int frame_count = 0;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000757 int jsframe_count = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000758 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
759 ++frame_count;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000760 if (e->frame_type() == JS_FUNCTION) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000761 ++jsframe_count;
762 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000763 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000764 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000765 WriteTranslation(environment, &translation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000766 int deoptimization_index = deoptimizations_.length();
erikcorry0ad885c2011-11-21 13:51:57 +0000767 int pc_offset = masm()->pc_offset();
768 environment->Register(deoptimization_index,
769 translation.index(),
770 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000771 deoptimizations_.Add(environment, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000772 }
773}
774
775
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000776void LCodeGen::DeoptimizeIf(Condition condition,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000777 LEnvironment* environment,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000778 Deoptimizer::BailoutType bailout_type,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000779 Register src1,
780 const Operand& src2) {
erikcorry0ad885c2011-11-21 13:51:57 +0000781 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000782 ASSERT(environment->HasBeenRegistered());
783 int id = environment->deoptimization_index();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000784 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000785 Address entry =
786 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000787 if (entry == NULL) {
danno@chromium.org59400602013-08-13 17:09:37 +0000788 Abort(kBailoutWasNotPrepared);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000789 return;
790 }
791
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000792 if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
793 Register scratch = scratch0();
794 ExternalReference count = ExternalReference::stress_deopt_count(isolate());
795 Label no_deopt;
796 __ Push(a1, scratch);
797 __ li(scratch, Operand(count));
798 __ lw(a1, MemOperand(scratch));
799 __ Subu(a1, a1, Operand(1));
800 __ Branch(&no_deopt, ne, a1, Operand(zero_reg));
801 __ li(a1, Operand(FLAG_deopt_every_n_times));
802 __ sw(a1, MemOperand(scratch));
803 __ Pop(a1, scratch);
804
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000805 __ Call(entry, RelocInfo::RUNTIME_ENTRY);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000806 __ bind(&no_deopt);
807 __ sw(a1, MemOperand(scratch));
808 __ Pop(a1, scratch);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000809 }
810
danno@chromium.org59400602013-08-13 17:09:37 +0000811 if (info()->ShouldTrapOnDeopt()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 Label skip;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000813 if (condition != al) {
814 __ Branch(&skip, NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000815 }
816 __ stop("trap_on_deopt");
817 __ bind(&skip);
818 }
819
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000820 ASSERT(info()->IsStub() || frame_is_built_);
machenbach@chromium.orgf9841892013-11-25 12:01:13 +0000821 // Go through jump table if we need to handle condition, build frame, or
822 // restore caller doubles.
823 if (condition == al && frame_is_built_ &&
824 !info()->saves_caller_doubles()) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000825 __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000826 } else {
827 // We often have several deopts to the same entry, reuse the last
828 // jump entry if this is the case.
829 if (deopt_jump_table_.is_empty() ||
830 (deopt_jump_table_.last().address != entry) ||
palfia@homejinni.com04109732013-05-15 09:50:32 +0000831 (deopt_jump_table_.last().bailout_type != bailout_type) ||
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000832 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000833 Deoptimizer::JumpTableEntry table_entry(entry,
834 bailout_type,
835 !frame_is_built_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000836 deopt_jump_table_.Add(table_entry, zone());
837 }
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000838 __ Branch(&deopt_jump_table_.last().label, condition, src1, src2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000839 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000840}
841
842
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000843void LCodeGen::DeoptimizeIf(Condition condition,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000844 LEnvironment* environment,
845 Register src1,
846 const Operand& src2) {
847 Deoptimizer::BailoutType bailout_type = info()->IsStub()
848 ? Deoptimizer::LAZY
849 : Deoptimizer::EAGER;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +0000850 DeoptimizeIf(condition, environment, bailout_type, src1, src2);
palfia@homejinni.com04109732013-05-15 09:50:32 +0000851}
852
853
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000854void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
855 int length = deoptimizations_.length();
856 if (length == 0) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000857 Handle<DeoptimizationInputData> data =
858 factory()->NewDeoptimizationInputData(length, TENURED);
859
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000860 Handle<ByteArray> translations =
861 translations_.CreateByteArray(isolate()->factory());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000862 data->SetTranslationByteArray(*translations);
863 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
864
865 Handle<FixedArray> literals =
866 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000867 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000868 for (int i = 0; i < deoptimization_literals_.length(); i++) {
869 literals->set(i, *deoptimization_literals_[i]);
870 }
871 data->SetLiteralArray(*literals);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000872 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000873
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000874 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000875 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
876
877 // Populate the deoptimization entries.
878 for (int i = 0; i < length; i++) {
879 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000880 data->SetAstId(i, env->ast_id());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000881 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
882 data->SetArgumentsStackHeight(i,
883 Smi::FromInt(env->arguments_stack_height()));
erikcorry0ad885c2011-11-21 13:51:57 +0000884 data->SetPc(i, Smi::FromInt(env->pc_offset()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000885 }
886 code->set_deoptimization_data(*data);
887}
888
889
890int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
891 int result = deoptimization_literals_.length();
892 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
893 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
894 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000895 deoptimization_literals_.Add(literal, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000896 return result;
897}
898
899
900void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
901 ASSERT(deoptimization_literals_.length() == 0);
902
903 const ZoneList<Handle<JSFunction> >* inlined_closures =
904 chunk()->inlined_closures();
905
906 for (int i = 0, length = inlined_closures->length();
907 i < length;
908 i++) {
909 DefineDeoptimizationLiteral(inlined_closures->at(i));
910 }
911
912 inlined_function_count_ = deoptimization_literals_.length();
913}
914
915
erikcorry0ad885c2011-11-21 13:51:57 +0000916void LCodeGen::RecordSafepointWithLazyDeopt(
917 LInstruction* instr, SafepointMode safepoint_mode) {
918 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
919 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
920 } else {
921 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
922 RecordSafepointWithRegisters(
923 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
924 }
925}
926
927
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000928void LCodeGen::RecordSafepoint(
929 LPointerMap* pointers,
930 Safepoint::Kind kind,
931 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000932 Safepoint::DeoptMode deopt_mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000933 ASSERT(expected_safepoint_kind_ == kind);
934
935 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
936 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
erikcorry0ad885c2011-11-21 13:51:57 +0000937 kind, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000938 for (int i = 0; i < operands->length(); i++) {
939 LOperand* pointer = operands->at(i);
940 if (pointer->IsStackSlot()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000941 safepoint.DefinePointerSlot(pointer->index(), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000942 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000943 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000944 }
945 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000946}
947
948
949void LCodeGen::RecordSafepoint(LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +0000950 Safepoint::DeoptMode deopt_mode) {
951 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000952}
953
954
erikcorry0ad885c2011-11-21 13:51:57 +0000955void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000956 LPointerMap empty_pointers(zone());
erikcorry0ad885c2011-11-21 13:51:57 +0000957 RecordSafepoint(&empty_pointers, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000958}
959
960
961void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
962 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000963 Safepoint::DeoptMode deopt_mode) {
964 RecordSafepoint(
965 pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000966}
967
968
969void LCodeGen::RecordSafepointWithRegistersAndDoubles(
970 LPointerMap* pointers,
971 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000972 Safepoint::DeoptMode deopt_mode) {
973 RecordSafepoint(
974 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000975}
976
977
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000978void LCodeGen::RecordAndWritePosition(int position) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000979 if (position == RelocInfo::kNoPosition) return;
980 masm()->positions_recorder()->RecordPosition(position);
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +0000981 masm()->positions_recorder()->WriteRecordedPositions();
danno@chromium.org59400602013-08-13 17:09:37 +0000982}
983
984
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000985static const char* LabelType(LLabel* label) {
986 if (label->is_loop_header()) return " (loop header)";
987 if (label->is_osr_entry()) return " (OSR entry)";
988 return "";
989}
990
991
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000992void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000993 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
994 current_instruction_,
995 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000996 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000997 LabelType(label));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000998 __ bind(label->label());
999 current_block_ = label->block_id();
1000 DoGap(label);
1001}
1002
1003
1004void LCodeGen::DoParallelMove(LParallelMove* move) {
1005 resolver_.Resolve(move);
1006}
1007
1008
1009void LCodeGen::DoGap(LGap* gap) {
1010 for (int i = LGap::FIRST_INNER_POSITION;
1011 i <= LGap::LAST_INNER_POSITION;
1012 i++) {
1013 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1014 LParallelMove* move = gap->GetParallelMove(inner_pos);
1015 if (move != NULL) DoParallelMove(move);
1016 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001017}
1018
1019
1020void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1021 DoGap(instr);
1022}
1023
1024
1025void LCodeGen::DoParameter(LParameter* instr) {
1026 // Nothing to do.
1027}
1028
1029
1030void LCodeGen::DoCallStub(LCallStub* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001031 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001032 ASSERT(ToRegister(instr->result()).is(v0));
1033 switch (instr->hydrogen()->major_key()) {
1034 case CodeStub::RegExpConstructResult: {
1035 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001036 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001037 break;
1038 }
1039 case CodeStub::RegExpExec: {
1040 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001041 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001042 break;
1043 }
1044 case CodeStub::SubString: {
1045 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001046 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001047 break;
1048 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001049 case CodeStub::StringCompare: {
1050 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001051 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001052 break;
1053 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001054 default:
1055 UNREACHABLE();
1056 }
1057}
1058
1059
1060void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00001061 GenerateOsrPrologue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001062}
1063
1064
1065void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001066 HMod* hmod = instr->hydrogen();
1067 HValue* left = hmod->left();
1068 HValue* right = hmod->right();
1069 if (hmod->HasPowerOf2Divisor()) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001070 const Register left_reg = ToRegister(instr->left());
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001071 const Register result_reg = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001072
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001073 // Note: The code below even works when right contains kMinInt.
1074 int32_t divisor = Abs(right->GetInteger32Constant());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001075
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001076 Label left_is_not_negative, done;
1077 if (left->CanBeNegative()) {
danno@chromium.orgc16e8282013-08-12 16:17:40 +00001078 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT,
1079 &left_is_not_negative, ge, left_reg, Operand(zero_reg));
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001080 __ subu(result_reg, zero_reg, left_reg);
1081 __ And(result_reg, result_reg, divisor - 1);
1082 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1083 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1084 }
1085 __ Branch(USE_DELAY_SLOT, &done);
1086 __ subu(result_reg, zero_reg, result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001087 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001088
1089 __ bind(&left_is_not_negative);
danno@chromium.orgc16e8282013-08-12 16:17:40 +00001090 __ And(result_reg, left_reg, divisor - 1);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001091 __ bind(&done);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001092 } else {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001093 const Register scratch = scratch0();
1094 const Register left_reg = ToRegister(instr->left());
1095 const Register result_reg = ToRegister(instr->result());
1096
1097 // div runs in the background while we check for special cases.
1098 Register right_reg = EmitLoadRegister(instr->right(), scratch);
1099 __ div(left_reg, right_reg);
1100
1101 Label done;
1102 // Check for x % 0, we have to deopt in this case because we can't return a
1103 // NaN.
1104 if (right->CanBeZero()) {
1105 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001106 }
1107
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001108 // Check for kMinInt % -1, we have to deopt if we care about -0, because we
1109 // can't return that.
1110 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001111 Label left_not_min_int;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001112 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt));
1113 // TODO(svenpanne) Don't deopt when we don't care about -0.
1114 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001115 __ bind(&left_not_min_int);
1116 }
1117
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001118 // TODO(svenpanne) Only emit the test/deopt if we have to.
1119 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg));
1120 __ mfhi(result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001121
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001122 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1123 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001124 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001125 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001126 }
1127}
1128
1129
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001130void LCodeGen::EmitSignedIntegerDivisionByConstant(
1131 Register result,
1132 Register dividend,
1133 int32_t divisor,
1134 Register remainder,
1135 Register scratch,
1136 LEnvironment* environment) {
1137 ASSERT(!AreAliased(dividend, scratch, at, no_reg));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001138
1139 uint32_t divisor_abs = abs(divisor);
1140
1141 int32_t power_of_2_factor =
1142 CompilerIntrinsics::CountTrailingZeros(divisor_abs);
1143
1144 switch (divisor_abs) {
1145 case 0:
1146 DeoptimizeIf(al, environment);
1147 return;
1148
1149 case 1:
1150 if (divisor > 0) {
1151 __ Move(result, dividend);
1152 } else {
1153 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch);
1154 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg));
1155 }
1156 // Compute the remainder.
1157 __ Move(remainder, zero_reg);
1158 return;
1159
1160 default:
1161 if (IsPowerOf2(divisor_abs)) {
1162 // Branch and condition free code for integer division by a power
1163 // of two.
1164 int32_t power = WhichPowerOf2(divisor_abs);
1165 if (power > 1) {
1166 __ sra(scratch, dividend, power - 1);
1167 }
1168 __ srl(scratch, scratch, 32 - power);
1169 __ Addu(scratch, dividend, Operand(scratch));
1170 __ sra(result, scratch, power);
1171 // Negate if necessary.
1172 // We don't need to check for overflow because the case '-1' is
1173 // handled separately.
1174 if (divisor < 0) {
1175 ASSERT(divisor != -1);
1176 __ Subu(result, zero_reg, Operand(result));
1177 }
1178 // Compute the remainder.
1179 if (divisor > 0) {
1180 __ sll(scratch, result, power);
1181 __ Subu(remainder, dividend, Operand(scratch));
1182 } else {
1183 __ sll(scratch, result, power);
1184 __ Addu(remainder, dividend, Operand(scratch));
1185 }
1186 return;
1187 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) {
1188 // Use magic numbers for a few specific divisors.
1189 // Details and proofs can be found in:
1190 // - Hacker's Delight, Henry S. Warren, Jr.
1191 // - The PowerPC Compiler Writer's Guide
1192 // and probably many others.
1193 //
1194 // We handle
1195 // <divisor with magic numbers> * <power of 2>
1196 // but not
1197 // <divisor with magic numbers> * <other divisor with magic numbers>
1198 DivMagicNumbers magic_numbers =
1199 DivMagicNumberFor(divisor_abs >> power_of_2_factor);
1200 // Branch and condition free code for integer division by a power
1201 // of two.
1202 const int32_t M = magic_numbers.M;
1203 const int32_t s = magic_numbers.s + power_of_2_factor;
1204
1205 __ li(scratch, Operand(M));
1206 __ mult(dividend, scratch);
1207 __ mfhi(scratch);
1208 if (M < 0) {
1209 __ Addu(scratch, scratch, Operand(dividend));
1210 }
1211 if (s > 0) {
1212 __ sra(scratch, scratch, s);
1213 __ mov(scratch, scratch);
1214 }
1215 __ srl(at, dividend, 31);
1216 __ Addu(result, scratch, Operand(at));
1217 if (divisor < 0) __ Subu(result, zero_reg, Operand(result));
1218 // Compute the remainder.
1219 __ li(scratch, Operand(divisor));
1220 __ Mul(scratch, result, Operand(scratch));
1221 __ Subu(remainder, dividend, Operand(scratch));
1222 } else {
1223 __ li(scratch, Operand(divisor));
1224 __ div(dividend, scratch);
1225 __ mfhi(remainder);
1226 __ mflo(result);
1227 }
1228 }
1229}
1230
1231
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001232void LCodeGen::DoDivI(LDivI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001233 const Register left = ToRegister(instr->left());
1234 const Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001235 const Register result = ToRegister(instr->result());
1236
1237 // On MIPS div is asynchronous - it will run in the background while we
1238 // check for special cases.
1239 __ div(left, right);
1240
1241 // Check for x / 0.
1242 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1243 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1244 }
1245
1246 // Check for (0 / -x) that will produce negative zero.
1247 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1248 Label left_not_zero;
1249 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1250 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1251 __ bind(&left_not_zero);
1252 }
1253
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001254 // Check for (kMinInt / -1).
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001255 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1256 Label left_not_min_int;
1257 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1258 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1259 __ bind(&left_not_min_int);
1260 }
1261
danno@chromium.org41728482013-06-12 22:31:22 +00001262 if (!instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1263 __ mfhi(result);
1264 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg));
1265 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001266 __ mflo(result);
1267}
1268
1269
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001270void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
1271 DoubleRegister addend = ToDoubleRegister(instr->addend());
1272 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
1273 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
1274
1275 // This is computed in-place.
1276 ASSERT(addend.is(ToDoubleRegister(instr->result())));
1277
1278 __ madd_d(addend, addend, multiplier, multiplicand);
1279}
1280
1281
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001282void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1283 const Register result = ToRegister(instr->result());
1284 const Register left = ToRegister(instr->left());
1285 const Register remainder = ToRegister(instr->temp());
1286 const Register scratch = scratch0();
1287
1288 if (instr->right()->IsConstantOperand()) {
1289 Label done;
1290 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
1291 if (divisor < 0) {
1292 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1293 }
1294 EmitSignedIntegerDivisionByConstant(result,
1295 left,
1296 divisor,
1297 remainder,
1298 scratch,
1299 instr->environment());
1300 // We performed a truncating division. Correct the result if necessary.
1301 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1302 __ Xor(scratch , remainder, Operand(divisor));
1303 __ Branch(&done, ge, scratch, Operand(zero_reg));
1304 __ Subu(result, result, Operand(1));
1305 __ bind(&done);
1306 } else {
1307 Label done;
1308 const Register right = ToRegister(instr->right());
1309
1310 // On MIPS div is asynchronous - it will run in the background while we
1311 // check for special cases.
1312 __ div(left, right);
1313
1314 // Check for x / 0.
1315 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1316
1317 // Check for (0 / -x) that will produce negative zero.
1318 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1319 Label left_not_zero;
1320 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1321 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1322 __ bind(&left_not_zero);
1323 }
1324
1325 // Check for (kMinInt / -1).
1326 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1327 Label left_not_min_int;
1328 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1329 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1330 __ bind(&left_not_min_int);
1331 }
1332
1333 __ mfhi(remainder);
1334 __ mflo(result);
1335
1336 // We performed a truncating division. Correct the result if necessary.
1337 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1338 __ Xor(scratch , remainder, Operand(right));
1339 __ Branch(&done, ge, scratch, Operand(zero_reg));
1340 __ Subu(result, result, Operand(1));
1341 __ bind(&done);
1342 }
1343}
1344
1345
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001346void LCodeGen::DoMulI(LMulI* instr) {
1347 Register scratch = scratch0();
1348 Register result = ToRegister(instr->result());
1349 // Note that result may alias left.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001350 Register left = ToRegister(instr->left());
1351 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001352
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001353 bool bailout_on_minus_zero =
1354 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001355 bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001356
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001357 if (right_op->IsConstantOperand()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001358 int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001359
1360 if (bailout_on_minus_zero && (constant < 0)) {
1361 // The case of a null constant will be handled separately.
1362 // If constant is negative and left is null, the result should be -0.
1363 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1364 }
1365
1366 switch (constant) {
1367 case -1:
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001368 if (overflow) {
1369 __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
1370 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
1371 } else {
1372 __ Subu(result, zero_reg, left);
1373 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001374 break;
1375 case 0:
1376 if (bailout_on_minus_zero) {
1377 // If left is strictly negative and the constant is null, the
1378 // result is -0. Deoptimize if required, otherwise return 0.
1379 DeoptimizeIf(lt, instr->environment(), left, Operand(zero_reg));
1380 }
1381 __ mov(result, zero_reg);
1382 break;
1383 case 1:
1384 // Nothing to do.
1385 __ Move(result, left);
1386 break;
1387 default:
1388 // Multiplying by powers of two and powers of two plus or minus
1389 // one can be done faster with shifted operands.
1390 // For other constants we emit standard code.
1391 int32_t mask = constant >> 31;
1392 uint32_t constant_abs = (constant + mask) ^ mask;
1393
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001394 if (IsPowerOf2(constant_abs)) {
1395 int32_t shift = WhichPowerOf2(constant_abs);
1396 __ sll(result, left, shift);
1397 // Correct the sign of the result if the constant is negative.
1398 if (constant < 0) __ Subu(result, zero_reg, result);
1399 } else if (IsPowerOf2(constant_abs - 1)) {
1400 int32_t shift = WhichPowerOf2(constant_abs - 1);
1401 __ sll(scratch, left, shift);
1402 __ Addu(result, scratch, left);
1403 // Correct the sign of the result if the constant is negative.
1404 if (constant < 0) __ Subu(result, zero_reg, result);
1405 } else if (IsPowerOf2(constant_abs + 1)) {
1406 int32_t shift = WhichPowerOf2(constant_abs + 1);
1407 __ sll(scratch, left, shift);
1408 __ Subu(result, scratch, left);
1409 // Correct the sign of the result if the constant is negative.
1410 if (constant < 0) __ Subu(result, zero_reg, result);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001411 } else {
1412 // Generate standard code.
1413 __ li(at, constant);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001414 __ Mul(result, left, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001415 }
1416 }
1417
1418 } else {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001419 ASSERT(right_op->IsRegister());
1420 Register right = ToRegister(right_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001421
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001422 if (overflow) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001423 // hi:lo = left * right.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001424 if (instr->hydrogen()->representation().IsSmi()) {
1425 __ SmiUntag(result, left);
1426 __ mult(result, right);
1427 __ mfhi(scratch);
1428 __ mflo(result);
1429 } else {
1430 __ mult(left, right);
1431 __ mfhi(scratch);
1432 __ mflo(result);
1433 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001434 __ sra(at, result, 31);
1435 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
1436 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001437 if (instr->hydrogen()->representation().IsSmi()) {
1438 __ SmiUntag(result, left);
1439 __ Mul(result, result, right);
1440 } else {
1441 __ Mul(result, left, right);
1442 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001443 }
1444
1445 if (bailout_on_minus_zero) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001446 Label done;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001447 __ Xor(at, left, right);
1448 __ Branch(&done, ge, at, Operand(zero_reg));
1449 // Bail out if the result is minus zero.
1450 DeoptimizeIf(eq,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001451 instr->environment(),
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00001452 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001453 Operand(zero_reg));
1454 __ bind(&done);
1455 }
1456 }
1457}
1458
1459
1460void LCodeGen::DoBitI(LBitI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001461 LOperand* left_op = instr->left();
1462 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001463 ASSERT(left_op->IsRegister());
1464 Register left = ToRegister(left_op);
1465 Register result = ToRegister(instr->result());
1466 Operand right(no_reg);
1467
1468 if (right_op->IsStackSlot() || right_op->IsArgument()) {
1469 right = Operand(EmitLoadRegister(right_op, at));
1470 } else {
1471 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
1472 right = ToOperand(right_op);
1473 }
1474
1475 switch (instr->op()) {
1476 case Token::BIT_AND:
1477 __ And(result, left, right);
1478 break;
1479 case Token::BIT_OR:
1480 __ Or(result, left, right);
1481 break;
1482 case Token::BIT_XOR:
danno@chromium.org59400602013-08-13 17:09:37 +00001483 if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) {
1484 __ Nor(result, zero_reg, left);
1485 } else {
1486 __ Xor(result, left, right);
1487 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001488 break;
1489 default:
1490 UNREACHABLE();
1491 break;
1492 }
1493}
1494
1495
1496void LCodeGen::DoShiftI(LShiftI* instr) {
1497 // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
1498 // result may alias either of them.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001499 LOperand* right_op = instr->right();
1500 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001501 Register result = ToRegister(instr->result());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001502 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001503
1504 if (right_op->IsRegister()) {
1505 // No need to mask the right operand on MIPS, it is built into the variable
1506 // shift instructions.
1507 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001508 case Token::ROR:
1509 __ Ror(result, left, Operand(ToRegister(right_op)));
1510 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001511 case Token::SAR:
1512 __ srav(result, left, ToRegister(right_op));
1513 break;
1514 case Token::SHR:
1515 __ srlv(result, left, ToRegister(right_op));
1516 if (instr->can_deopt()) {
1517 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
1518 }
1519 break;
1520 case Token::SHL:
1521 __ sllv(result, left, ToRegister(right_op));
1522 break;
1523 default:
1524 UNREACHABLE();
1525 break;
1526 }
1527 } else {
1528 // Mask the right_op operand.
1529 int value = ToInteger32(LConstantOperand::cast(right_op));
1530 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1531 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001532 case Token::ROR:
1533 if (shift_count != 0) {
1534 __ Ror(result, left, Operand(shift_count));
1535 } else {
1536 __ Move(result, left);
1537 }
1538 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001539 case Token::SAR:
1540 if (shift_count != 0) {
1541 __ sra(result, left, shift_count);
1542 } else {
1543 __ Move(result, left);
1544 }
1545 break;
1546 case Token::SHR:
1547 if (shift_count != 0) {
1548 __ srl(result, left, shift_count);
1549 } else {
1550 if (instr->can_deopt()) {
1551 __ And(at, left, Operand(0x80000000));
1552 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
1553 }
1554 __ Move(result, left);
1555 }
1556 break;
1557 case Token::SHL:
1558 if (shift_count != 0) {
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001559 if (instr->hydrogen_value()->representation().IsSmi() &&
1560 instr->can_deopt()) {
1561 if (shift_count != 1) {
1562 __ sll(result, left, shift_count - 1);
1563 __ SmiTagCheckOverflow(result, result, scratch);
1564 } else {
1565 __ SmiTagCheckOverflow(result, left, scratch);
1566 }
1567 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
1568 } else {
1569 __ sll(result, left, shift_count);
1570 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001571 } else {
1572 __ Move(result, left);
1573 }
1574 break;
1575 default:
1576 UNREACHABLE();
1577 break;
1578 }
1579 }
1580}
1581
1582
1583void LCodeGen::DoSubI(LSubI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001584 LOperand* left = instr->left();
1585 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001586 LOperand* result = instr->result();
1587 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1588
1589 if (!can_overflow) {
1590 if (right->IsStackSlot() || right->IsArgument()) {
1591 Register right_reg = EmitLoadRegister(right, at);
1592 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg));
1593 } else {
1594 ASSERT(right->IsRegister() || right->IsConstantOperand());
1595 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
1596 }
1597 } else { // can_overflow.
1598 Register overflow = scratch0();
1599 Register scratch = scratch1();
1600 if (right->IsStackSlot() ||
1601 right->IsArgument() ||
1602 right->IsConstantOperand()) {
1603 Register right_reg = EmitLoadRegister(right, scratch);
1604 __ SubuAndCheckForOverflow(ToRegister(result),
1605 ToRegister(left),
1606 right_reg,
1607 overflow); // Reg at also used as scratch.
1608 } else {
1609 ASSERT(right->IsRegister());
1610 // Due to overflow check macros not supporting constant operands,
1611 // handling the IsConstantOperand case was moved to prev if clause.
1612 __ SubuAndCheckForOverflow(ToRegister(result),
1613 ToRegister(left),
1614 ToRegister(right),
1615 overflow); // Reg at also used as scratch.
1616 }
1617 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1618 }
1619}
1620
1621
1622void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001623 __ li(ToRegister(instr->result()), Operand(instr->value()));
1624}
1625
1626
1627void LCodeGen::DoConstantS(LConstantS* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001628 __ li(ToRegister(instr->result()), Operand(instr->value()));
1629}
1630
1631
1632void LCodeGen::DoConstantD(LConstantD* instr) {
1633 ASSERT(instr->result()->IsDoubleRegister());
1634 DoubleRegister result = ToDoubleRegister(instr->result());
1635 double v = instr->value();
1636 __ Move(result, v);
1637}
1638
1639
danno@chromium.orgd3c42102013-08-01 16:58:23 +00001640void LCodeGen::DoConstantE(LConstantE* instr) {
1641 __ li(ToRegister(instr->result()), Operand(instr->value()));
1642}
1643
1644
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001645void LCodeGen::DoConstantT(LConstantT* instr) {
palfia@homejinni.com8b6c7862013-09-10 15:12:05 +00001646 Handle<Object> value = instr->value(isolate());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001647 AllowDeferredHandleDereference smi_check;
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001648 __ li(ToRegister(instr->result()), value);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649}
1650
1651
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001652void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1653 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001654 Register map = ToRegister(instr->value());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001655 __ EnumLength(result, map);
1656}
1657
1658
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001659void LCodeGen::DoElementsKind(LElementsKind* instr) {
1660 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001661 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001662
1663 // Load map into |result|.
1664 __ lw(result, FieldMemOperand(input, HeapObject::kMapOffset));
1665 // Load the map's "bit field 2" into |result|. We only need the first byte,
1666 // but the following bit field extraction takes care of that anyway.
1667 __ lbu(result, FieldMemOperand(result, Map::kBitField2Offset));
1668 // Retrieve elements_kind from bit field 2.
1669 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
1670}
1671
1672
1673void LCodeGen::DoValueOf(LValueOf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001674 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001675 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001676 Register map = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001677 Label done;
1678
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001679 if (!instr->hydrogen()->value()->IsHeapObject()) {
1680 // If the object is a smi return the object.
1681 __ Move(result, input);
1682 __ JumpIfSmi(input, &done);
1683 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001684
1685 // If the object is not a value type, return the object.
1686 __ GetObjectType(input, map, map);
1687 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE));
1688 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset));
1689
1690 __ bind(&done);
1691}
1692
1693
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001694void LCodeGen::DoDateField(LDateField* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001695 Register object = ToRegister(instr->date());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001696 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001697 Register scratch = ToRegister(instr->temp());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001698 Smi* index = instr->index();
1699 Label runtime, done;
1700 ASSERT(object.is(a0));
1701 ASSERT(result.is(v0));
1702 ASSERT(!scratch.is(scratch0()));
1703 ASSERT(!scratch.is(object));
1704
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001705 __ SmiTst(object, at);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001706 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001707 __ GetObjectType(object, scratch, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001708 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001709
1710 if (index->value() == 0) {
1711 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
1712 } else {
1713 if (index->value() < JSDate::kFirstUncachedField) {
1714 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1715 __ li(scratch, Operand(stamp));
1716 __ lw(scratch, MemOperand(scratch));
1717 __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
1718 __ Branch(&runtime, ne, scratch, Operand(scratch0()));
1719 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
1720 kPointerSize * index->value()));
1721 __ jmp(&done);
1722 }
1723 __ bind(&runtime);
1724 __ PrepareCallCFunction(2, scratch);
1725 __ li(a1, Operand(index));
1726 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1727 __ bind(&done);
1728 }
1729}
1730
1731
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001732MemOperand LCodeGen::BuildSeqStringOperand(Register string,
1733 LOperand* index,
1734 String::Encoding encoding) {
1735 if (index->IsConstantOperand()) {
1736 int offset = ToInteger32(LConstantOperand::cast(index));
1737 if (encoding == String::TWO_BYTE_ENCODING) {
1738 offset *= kUC16Size;
1739 }
1740 STATIC_ASSERT(kCharSize == 1);
1741 return FieldMemOperand(string, SeqString::kHeaderSize + offset);
1742 }
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001743 Register scratch = scratch0();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001744 ASSERT(!scratch.is(string));
1745 ASSERT(!scratch.is(ToRegister(index)));
1746 if (encoding == String::ONE_BYTE_ENCODING) {
1747 __ Addu(scratch, string, ToRegister(index));
1748 } else {
1749 STATIC_ASSERT(kUC16Size == 2);
1750 __ sll(scratch, ToRegister(index), 1);
1751 __ Addu(scratch, string, scratch);
1752 }
1753 return FieldMemOperand(scratch, SeqString::kHeaderSize);
1754}
1755
1756
1757void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
1758 String::Encoding encoding = instr->hydrogen()->encoding();
1759 Register string = ToRegister(instr->string());
1760 Register result = ToRegister(instr->result());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001761
1762 if (FLAG_debug_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001763 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001764 __ lw(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
1765 __ lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001766
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001767 __ And(scratch, scratch,
1768 Operand(kStringRepresentationMask | kStringEncodingMask));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001769 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1770 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001771 __ Subu(at, scratch, Operand(encoding == String::ONE_BYTE_ENCODING
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001772 ? one_byte_seq_type : two_byte_seq_type));
danno@chromium.org59400602013-08-13 17:09:37 +00001773 __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001774 }
1775
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001776 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1777 if (encoding == String::ONE_BYTE_ENCODING) {
1778 __ lbu(result, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001779 } else {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001780 __ lhu(result, operand);
1781 }
1782}
1783
1784
1785void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
1786 String::Encoding encoding = instr->hydrogen()->encoding();
1787 Register string = ToRegister(instr->string());
1788 Register value = ToRegister(instr->value());
1789
1790 if (FLAG_debug_code) {
1791 Register scratch = scratch0();
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001792 Register index = ToRegister(instr->index());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001793 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1794 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00001795 int encoding_mask =
1796 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
1797 ? one_byte_seq_type : two_byte_seq_type;
1798 __ EmitSeqStringSetCharCheck(string, index, value, scratch, encoding_mask);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001799 }
1800
1801 MemOperand operand = BuildSeqStringOperand(string, instr->index(), encoding);
1802 if (encoding == String::ONE_BYTE_ENCODING) {
1803 __ sb(value, operand);
1804 } else {
1805 __ sh(value, operand);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001806 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001807}
1808
1809
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001810void LCodeGen::DoThrow(LThrow* instr) {
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001811 __ push(ToRegister(instr->value()));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001812 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001813 CallRuntime(Runtime::kThrow, 1, instr);
1814
1815 if (FLAG_debug_code) {
1816 __ stop("Unreachable code.");
1817 }
1818}
1819
1820
1821void LCodeGen::DoAddI(LAddI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001822 LOperand* left = instr->left();
1823 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 LOperand* result = instr->result();
1825 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1826
1827 if (!can_overflow) {
1828 if (right->IsStackSlot() || right->IsArgument()) {
1829 Register right_reg = EmitLoadRegister(right, at);
1830 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg));
1831 } else {
1832 ASSERT(right->IsRegister() || right->IsConstantOperand());
1833 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
1834 }
1835 } else { // can_overflow.
1836 Register overflow = scratch0();
1837 Register scratch = scratch1();
1838 if (right->IsStackSlot() ||
1839 right->IsArgument() ||
1840 right->IsConstantOperand()) {
1841 Register right_reg = EmitLoadRegister(right, scratch);
1842 __ AdduAndCheckForOverflow(ToRegister(result),
1843 ToRegister(left),
1844 right_reg,
1845 overflow); // Reg at also used as scratch.
1846 } else {
1847 ASSERT(right->IsRegister());
1848 // Due to overflow check macros not supporting constant operands,
1849 // handling the IsConstantOperand case was moved to prev if clause.
1850 __ AdduAndCheckForOverflow(ToRegister(result),
1851 ToRegister(left),
1852 ToRegister(right),
1853 overflow); // Reg at also used as scratch.
1854 }
1855 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1856 }
1857}
1858
1859
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001860void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001861 LOperand* left = instr->left();
1862 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001863 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1864 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001865 if (instr->hydrogen()->representation().IsSmiOrInteger32()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001866 Register left_reg = ToRegister(left);
1867 Operand right_op = (right->IsRegister() || right->IsConstantOperand())
1868 ? ToOperand(right)
1869 : Operand(EmitLoadRegister(right, at));
1870 Register result_reg = ToRegister(instr->result());
1871 Label return_right, done;
1872 if (!result_reg.is(left_reg)) {
1873 __ Branch(&return_right, NegateCondition(condition), left_reg, right_op);
1874 __ mov(result_reg, left_reg);
1875 __ Branch(&done);
1876 }
1877 __ Branch(&done, condition, left_reg, right_op);
1878 __ bind(&return_right);
1879 __ Addu(result_reg, zero_reg, right_op);
1880 __ bind(&done);
1881 } else {
1882 ASSERT(instr->hydrogen()->representation().IsDouble());
1883 FPURegister left_reg = ToDoubleRegister(left);
1884 FPURegister right_reg = ToDoubleRegister(right);
1885 FPURegister result_reg = ToDoubleRegister(instr->result());
1886 Label check_nan_left, check_zero, return_left, return_right, done;
1887 __ BranchF(&check_zero, &check_nan_left, eq, left_reg, right_reg);
1888 __ BranchF(&return_left, NULL, condition, left_reg, right_reg);
1889 __ Branch(&return_right);
1890
1891 __ bind(&check_zero);
1892 // left == right != 0.
1893 __ BranchF(&return_left, NULL, ne, left_reg, kDoubleRegZero);
1894 // At this point, both left and right are either 0 or -0.
1895 if (operation == HMathMinMax::kMathMin) {
1896 __ neg_d(left_reg, left_reg);
1897 __ sub_d(result_reg, left_reg, right_reg);
1898 __ neg_d(result_reg, result_reg);
1899 } else {
1900 __ add_d(result_reg, left_reg, right_reg);
1901 }
1902 __ Branch(&done);
1903
1904 __ bind(&check_nan_left);
1905 // left == NaN.
1906 __ BranchF(NULL, &return_left, eq, left_reg, left_reg);
1907 __ bind(&return_right);
1908 if (!right_reg.is(result_reg)) {
1909 __ mov_d(result_reg, right_reg);
1910 }
1911 __ Branch(&done);
1912
1913 __ bind(&return_left);
1914 if (!left_reg.is(result_reg)) {
1915 __ mov_d(result_reg, left_reg);
1916 }
1917 __ bind(&done);
1918 }
1919}
1920
1921
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001922void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001923 DoubleRegister left = ToDoubleRegister(instr->left());
1924 DoubleRegister right = ToDoubleRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001925 DoubleRegister result = ToDoubleRegister(instr->result());
1926 switch (instr->op()) {
1927 case Token::ADD:
1928 __ add_d(result, left, right);
1929 break;
1930 case Token::SUB:
1931 __ sub_d(result, left, right);
1932 break;
1933 case Token::MUL:
1934 __ mul_d(result, left, right);
1935 break;
1936 case Token::DIV:
1937 __ div_d(result, left, right);
1938 break;
1939 case Token::MOD: {
1940 // Save a0-a3 on the stack.
1941 RegList saved_regs = a0.bit() | a1.bit() | a2.bit() | a3.bit();
1942 __ MultiPush(saved_regs);
1943
1944 __ PrepareCallCFunction(0, 2, scratch0());
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001945 __ MovToFloatParameters(left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001946 __ CallCFunction(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001947 ExternalReference::mod_two_doubles_operation(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001948 0, 2);
1949 // Move the result in the double result register.
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00001950 __ MovFromFloatResult(result);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001951
1952 // Restore saved register.
1953 __ MultiPop(saved_regs);
1954 break;
1955 }
1956 default:
1957 UNREACHABLE();
1958 break;
1959 }
1960}
1961
1962
1963void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00001964 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001965 ASSERT(ToRegister(instr->left()).is(a1));
1966 ASSERT(ToRegister(instr->right()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001967 ASSERT(ToRegister(instr->result()).is(v0));
1968
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00001969 BinaryOpICStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001970 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001971 // Other arch use a nop here, to signal that there is no inlined
1972 // patchable code. Mips does not need the nop, since our marker
1973 // instruction (andi zero_reg) will never be used in normal code.
1974}
1975
1976
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001977template<class InstrType>
1978void LCodeGen::EmitBranch(InstrType instr,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001979 Condition condition,
1980 Register src1,
1981 const Operand& src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001982 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001983 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001984
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001985 int next_block = GetNextEmittedBlock();
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001986 if (right_block == left_block || condition == al) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001987 EmitGoto(left_block);
1988 } else if (left_block == next_block) {
1989 __ Branch(chunk_->GetAssemblyLabel(right_block),
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001990 NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001991 } else if (right_block == next_block) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001992 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001993 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00001994 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001995 __ Branch(chunk_->GetAssemblyLabel(right_block));
1996 }
1997}
1998
1999
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002000template<class InstrType>
2001void LCodeGen::EmitBranchF(InstrType instr,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002002 Condition condition,
2003 FPURegister src1,
2004 FPURegister src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002005 int right_block = instr->FalseDestination(chunk_);
2006 int left_block = instr->TrueDestination(chunk_);
2007
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002008 int next_block = GetNextEmittedBlock();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002009 if (right_block == left_block) {
2010 EmitGoto(left_block);
2011 } else if (left_block == next_block) {
2012 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002013 NegateCondition(condition), src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002014 } else if (right_block == next_block) {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002015 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL,
2016 condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002018 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL,
2019 condition, src1, src2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020 __ Branch(chunk_->GetAssemblyLabel(right_block));
2021 }
2022}
2023
2024
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002025template<class InstrType>
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002026void LCodeGen::EmitFalseBranch(InstrType instr,
2027 Condition condition,
2028 Register src1,
2029 const Operand& src2) {
2030 int false_block = instr->FalseDestination(chunk_);
2031 __ Branch(chunk_->GetAssemblyLabel(false_block), condition, src1, src2);
2032}
2033
2034
2035template<class InstrType>
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002036void LCodeGen::EmitFalseBranchF(InstrType instr,
2037 Condition condition,
2038 FPURegister src1,
2039 FPURegister src2) {
2040 int false_block = instr->FalseDestination(chunk_);
2041 __ BranchF(chunk_->GetAssemblyLabel(false_block), NULL,
2042 condition, src1, src2);
2043}
2044
2045
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002046void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
2047 __ stop("LDebugBreak");
2048}
2049
2050
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002051void LCodeGen::DoBranch(LBranch* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002052 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002053 if (r.IsInteger32() || r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002054 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002055 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002056 EmitBranch(instr, ne, reg, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002057 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002058 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002059 DoubleRegister reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 // Test the double value. Zero and NaN are false.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002061 EmitBranchF(instr, nue, reg, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 } else {
2063 ASSERT(r.IsTagged());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002064 Register reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002065 HType type = instr->hydrogen()->value()->type();
2066 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002067 ASSERT(!info()->IsStub());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002068 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002069 EmitBranch(instr, eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002070 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002071 ASSERT(!info()->IsStub());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002072 EmitBranch(instr, ne, reg, Operand(zero_reg));
2073 } else if (type.IsJSArray()) {
2074 ASSERT(!info()->IsStub());
2075 EmitBranch(instr, al, zero_reg, Operand(zero_reg));
2076 } else if (type.IsHeapNumber()) {
2077 ASSERT(!info()->IsStub());
2078 DoubleRegister dbl_scratch = double_scratch0();
2079 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
2080 // Test the double value. Zero and NaN are false.
2081 EmitBranchF(instr, nue, dbl_scratch, kDoubleRegZero);
2082 } else if (type.IsString()) {
2083 ASSERT(!info()->IsStub());
2084 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
2085 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002086 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2088 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002089 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002090
2091 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2092 // undefined -> false.
2093 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002094 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 }
2096 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2097 // Boolean -> its value.
2098 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002099 __ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002100 __ LoadRoot(at, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002101 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002102 }
2103 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2104 // 'null' -> false.
2105 __ LoadRoot(at, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002106 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002107 }
2108
2109 if (expected.Contains(ToBooleanStub::SMI)) {
2110 // Smis: 0 -> false, all other -> true.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002111 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg));
2112 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002113 } else if (expected.NeedsMap()) {
2114 // If we need a map later and have a Smi -> deopt.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00002115 __ SmiTst(reg, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002116 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
2117 }
2118
2119 const Register map = scratch0();
2120 if (expected.NeedsMap()) {
2121 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset));
2122 if (expected.CanBeUndetectable()) {
2123 // Undetectable -> false.
2124 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
2125 __ And(at, at, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002126 __ Branch(instr->FalseLabel(chunk_), ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002127 }
2128 }
2129
2130 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2131 // spec object -> true.
2132 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002133 __ Branch(instr->TrueLabel(chunk_),
2134 ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002135 }
2136
2137 if (expected.Contains(ToBooleanStub::STRING)) {
2138 // String value -> false iff empty.
2139 Label not_string;
2140 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
2141 __ Branch(&not_string, ge , at, Operand(FIRST_NONSTRING_TYPE));
2142 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002143 __ Branch(instr->TrueLabel(chunk_), ne, at, Operand(zero_reg));
2144 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002145 __ bind(&not_string);
2146 }
2147
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002148 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2149 // Symbol value -> true.
2150 const Register scratch = scratch1();
2151 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002152 __ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002153 }
2154
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002155 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2156 // heap number -> false iff +0, -0, or NaN.
2157 DoubleRegister dbl_scratch = double_scratch0();
2158 Label not_heap_number;
2159 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
2160 __ Branch(&not_heap_number, ne, map, Operand(at));
2161 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002162 __ BranchF(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2163 ne, dbl_scratch, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002164 // Falls through if dbl_scratch == 0.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002165 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002166 __ bind(&not_heap_number);
2167 }
2168
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002169 if (!expected.IsGeneric()) {
2170 // We've seen something for the first time -> deopt.
2171 // This can only happen if we are not generic already.
2172 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
2173 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002174 }
2175 }
2176}
2177
2178
2179void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002180 if (!IsNextEmittedBlock(block)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002181 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002182 }
2183}
2184
2185
2186void LCodeGen::DoGoto(LGoto* instr) {
2187 EmitGoto(instr->block_id());
2188}
2189
2190
2191Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2192 Condition cond = kNoCondition;
2193 switch (op) {
2194 case Token::EQ:
2195 case Token::EQ_STRICT:
2196 cond = eq;
2197 break;
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00002198 case Token::NE:
2199 case Token::NE_STRICT:
2200 cond = ne;
2201 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002202 case Token::LT:
2203 cond = is_unsigned ? lo : lt;
2204 break;
2205 case Token::GT:
2206 cond = is_unsigned ? hi : gt;
2207 break;
2208 case Token::LTE:
2209 cond = is_unsigned ? ls : le;
2210 break;
2211 case Token::GTE:
2212 cond = is_unsigned ? hs : ge;
2213 break;
2214 case Token::IN:
2215 case Token::INSTANCEOF:
2216 default:
2217 UNREACHABLE();
2218 }
2219 return cond;
2220}
2221
2222
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002223void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002224 LOperand* left = instr->left();
2225 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002226 Condition cond = TokenToCondition(instr->op(), false);
2227
2228 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2229 // We can statically evaluate the comparison.
2230 double left_val = ToDouble(LConstantOperand::cast(left));
2231 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002232 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2233 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 EmitGoto(next_block);
2235 } else {
2236 if (instr->is_double()) {
2237 // Compare left and right as doubles and load the
2238 // resulting flags into the normal status register.
2239 FPURegister left_reg = ToDoubleRegister(left);
2240 FPURegister right_reg = ToDoubleRegister(right);
2241
2242 // If a NaN is involved, i.e. the result is unordered,
2243 // jump to false block label.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002244 __ BranchF(NULL, instr->FalseLabel(chunk_), eq,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002245 left_reg, right_reg);
2246
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002247 EmitBranchF(instr, cond, left_reg, right_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002248 } else {
2249 Register cmp_left;
2250 Operand cmp_right = Operand(0);
2251
2252 if (right->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002253 int32_t value = ToInteger32(LConstantOperand::cast(right));
2254 if (instr->hydrogen_value()->representation().IsSmi()) {
2255 cmp_left = ToRegister(left);
2256 cmp_right = Operand(Smi::FromInt(value));
2257 } else {
2258 cmp_left = ToRegister(left);
2259 cmp_right = Operand(value);
2260 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002261 } else if (left->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002262 int32_t value = ToInteger32(LConstantOperand::cast(left));
2263 if (instr->hydrogen_value()->representation().IsSmi()) {
2264 cmp_left = ToRegister(right);
2265 cmp_right = Operand(Smi::FromInt(value));
2266 } else {
2267 cmp_left = ToRegister(right);
2268 cmp_right = Operand(value);
2269 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002270 // We transposed the operands. Reverse the condition.
2271 cond = ReverseCondition(cond);
2272 } else {
2273 cmp_left = ToRegister(left);
2274 cmp_right = Operand(ToRegister(right));
2275 }
2276
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002277 EmitBranch(instr, cond, cmp_left, cmp_right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002278 }
2279 }
2280}
2281
2282
2283void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002284 Register left = ToRegister(instr->left());
2285 Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002286
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002287 EmitBranch(instr, eq, left, Operand(right));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002288}
2289
2290
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00002291void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) {
2292 if (instr->hydrogen()->representation().IsTagged()) {
2293 Register input_reg = ToRegister(instr->object());
2294 __ li(at, Operand(factory()->the_hole_value()));
2295 EmitBranch(instr, eq, input_reg, Operand(at));
2296 return;
2297 }
2298
2299 DoubleRegister input_reg = ToDoubleRegister(instr->object());
2300 EmitFalseBranchF(instr, eq, input_reg, input_reg);
2301
2302 Register scratch = scratch0();
2303 __ FmoveHigh(scratch, input_reg);
2304 EmitBranch(instr, eq, scratch, Operand(kHoleNanUpper32));
2305}
2306
2307
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00002308void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
2309 Representation rep = instr->hydrogen()->value()->representation();
2310 ASSERT(!rep.IsInteger32());
2311 Register scratch = ToRegister(instr->temp());
2312
2313 if (rep.IsDouble()) {
2314 DoubleRegister value = ToDoubleRegister(instr->value());
2315 EmitFalseBranchF(instr, ne, value, kDoubleRegZero);
2316 __ FmoveHigh(scratch, value);
2317 __ li(at, 0x80000000);
2318 } else {
2319 Register value = ToRegister(instr->value());
2320 __ CheckMap(value,
2321 scratch,
2322 Heap::kHeapNumberMapRootIndex,
2323 instr->FalseLabel(chunk()),
2324 DO_SMI_CHECK);
2325 __ lw(scratch, FieldMemOperand(value, HeapNumber::kExponentOffset));
2326 EmitFalseBranch(instr, ne, scratch, Operand(0x80000000));
2327 __ lw(scratch, FieldMemOperand(value, HeapNumber::kMantissaOffset));
2328 __ mov(at, zero_reg);
2329 }
2330 EmitBranch(instr, eq, scratch, Operand(at));
2331}
2332
2333
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002334Condition LCodeGen::EmitIsObject(Register input,
2335 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +00002336 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002337 Label* is_not_object,
2338 Label* is_object) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002339 __ JumpIfSmi(input, is_not_object);
2340
2341 __ LoadRoot(temp2, Heap::kNullValueRootIndex);
2342 __ Branch(is_object, eq, input, Operand(temp2));
2343
2344 // Load map.
2345 __ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
2346 // Undetectable objects behave like undefined.
2347 __ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
2348 __ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
2349 __ Branch(is_not_object, ne, temp2, Operand(zero_reg));
2350
2351 // Load instance type and check that it is in object type range.
2352 __ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
2353 __ Branch(is_not_object,
2354 lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2355
2356 return le;
2357}
2358
2359
2360void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002361 Register reg = ToRegister(instr->value());
2362 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002363 Register temp2 = scratch0();
2364
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002365 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002366 EmitIsObject(reg, temp1, temp2,
2367 instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002368
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002369 EmitBranch(instr, true_cond, temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002370 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2371}
2372
2373
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002374Condition LCodeGen::EmitIsString(Register input,
2375 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002376 Label* is_not_string,
2377 SmiCheck check_needed = INLINE_SMI_CHECK) {
2378 if (check_needed == INLINE_SMI_CHECK) {
2379 __ JumpIfSmi(input, is_not_string);
2380 }
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002381 __ GetObjectType(input, temp1, temp1);
2382
2383 return lt;
2384}
2385
2386
2387void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002388 Register reg = ToRegister(instr->value());
2389 Register temp1 = ToRegister(instr->temp());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002390
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002391 SmiCheck check_needed =
2392 instr->hydrogen()->value()->IsHeapObject()
2393 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002394 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002395 EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002396
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002397 EmitBranch(instr, true_cond, temp1,
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002398 Operand(FIRST_NONSTRING_TYPE));
2399}
2400
2401
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002403 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002404 __ And(at, input_reg, kSmiTagMask);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002405 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002406}
2407
2408
2409void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002410 Register input = ToRegister(instr->value());
2411 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002412
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002413 if (!instr->hydrogen()->value()->IsHeapObject()) {
2414 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2415 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset));
2417 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
2418 __ And(at, temp, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002419 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420}
2421
2422
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002423static Condition ComputeCompareCondition(Token::Value op) {
2424 switch (op) {
2425 case Token::EQ_STRICT:
2426 case Token::EQ:
2427 return eq;
2428 case Token::LT:
2429 return lt;
2430 case Token::GT:
2431 return gt;
2432 case Token::LTE:
2433 return le;
2434 case Token::GTE:
2435 return ge;
2436 default:
2437 UNREACHABLE();
2438 return kNoCondition;
2439 }
2440}
2441
2442
2443void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002444 ASSERT(ToRegister(instr->context()).is(cp));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002445 Token::Value op = instr->op();
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002446
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002447 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002448 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2449
2450 Condition condition = ComputeCompareCondition(op);
2451
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002452 EmitBranch(instr, condition, v0, Operand(zero_reg));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002453}
2454
2455
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002456static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2457 InstanceType from = instr->from();
2458 InstanceType to = instr->to();
2459 if (from == FIRST_TYPE) return to;
2460 ASSERT(from == to || to == LAST_TYPE);
2461 return from;
2462}
2463
2464
2465static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2466 InstanceType from = instr->from();
2467 InstanceType to = instr->to();
2468 if (from == to) return eq;
2469 if (to == LAST_TYPE) return hs;
2470 if (from == FIRST_TYPE) return ls;
2471 UNREACHABLE();
2472 return eq;
2473}
2474
2475
2476void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2477 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002478 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002479
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002480 if (!instr->hydrogen()->value()->IsHeapObject()) {
2481 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2482 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002483
2484 __ GetObjectType(input, scratch, scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002485 EmitBranch(instr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002486 BranchCondition(instr->hydrogen()),
2487 scratch,
2488 Operand(TestType(instr->hydrogen())));
2489}
2490
2491
2492void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002493 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494 Register result = ToRegister(instr->result());
2495
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002496 __ AssertString(input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497
2498 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset));
2499 __ IndexFromHash(result, result);
2500}
2501
2502
2503void LCodeGen::DoHasCachedArrayIndexAndBranch(
2504 LHasCachedArrayIndexAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002505 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002506 Register scratch = scratch0();
2507
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002508 __ lw(scratch,
2509 FieldMemOperand(input, String::kHashFieldOffset));
2510 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002511 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002512}
2513
2514
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002515// Branches to a label or falls through with the answer in flags. Trashes
2516// the temp registers, but not the input.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002517void LCodeGen::EmitClassOfTest(Label* is_true,
2518 Label* is_false,
2519 Handle<String>class_name,
2520 Register input,
2521 Register temp,
2522 Register temp2) {
2523 ASSERT(!input.is(temp));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002524 ASSERT(!input.is(temp2));
2525 ASSERT(!temp.is(temp2));
2526
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002527 __ JumpIfSmi(input, is_false);
2528
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002529 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 // Assuming the following assertions, we can use the same compares to test
2531 // for both being a function type and being in the object type range.
2532 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2533 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2534 FIRST_SPEC_OBJECT_TYPE + 1);
2535 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2536 LAST_SPEC_OBJECT_TYPE - 1);
2537 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2538
2539 __ GetObjectType(input, temp, temp2);
2540 __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2541 __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2542 __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
2543 } else {
2544 // Faster code path to avoid two compares: subtract lower bound from the
2545 // actual type and do a signed compare with the width of the type range.
2546 __ GetObjectType(input, temp, temp2);
2547 __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2548 __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2549 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2550 }
2551
2552 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2553 // Check if the constructor in the map is a function.
2554 __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset));
2555
2556 // Objects with a non-function constructor have class 'Object'.
2557 __ GetObjectType(temp, temp2, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002558 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002559 __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
2560 } else {
2561 __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
2562 }
2563
2564 // temp now contains the constructor function. Grab the
2565 // instance class name from there.
2566 __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2567 __ lw(temp, FieldMemOperand(temp,
2568 SharedFunctionInfo::kInstanceClassNameOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002569 // The class name we are testing against is internalized since it's a literal.
2570 // The name in the constructor is internalized because of the way the context
2571 // is booted. This routine isn't expected to work for random API-created
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002572 // classes and it doesn't have to because you can't access it with natives
ulan@chromium.org750145a2013-03-07 15:14:13 +00002573 // syntax. Since both sides are internalized it is sufficient to use an
2574 // identity comparison.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002575
2576 // End with the address of this class_name instance in temp register.
2577 // On MIPS, the caller must do the comparison with Handle<String>class_name.
2578}
2579
2580
2581void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002582 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002583 Register temp = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002584 Register temp2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002585 Handle<String> class_name = instr->hydrogen()->class_name();
2586
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002587 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2588 class_name, input, temp, temp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002589
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002590 EmitBranch(instr, eq, temp, Operand(class_name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002591}
2592
2593
2594void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002595 Register reg = ToRegister(instr->value());
2596 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002597
2598 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002599 EmitBranch(instr, eq, temp, Operand(instr->map()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002600}
2601
2602
2603void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002604 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002605 Label true_label, done;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002606 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0.
2607 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002608 Register result = ToRegister(instr->result());
2609 ASSERT(result.is(v0));
2610
2611 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002612 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002613
2614 __ Branch(&true_label, eq, result, Operand(zero_reg));
2615 __ li(result, Operand(factory()->false_value()));
2616 __ Branch(&done);
2617 __ bind(&true_label);
2618 __ li(result, Operand(factory()->true_value()));
2619 __ bind(&done);
2620}
2621
2622
2623void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002624 class DeferredInstanceOfKnownGlobal V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002625 public:
2626 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2627 LInstanceOfKnownGlobal* instr)
2628 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002629 virtual void Generate() V8_OVERRIDE {
erikcorry0ad885c2011-11-21 13:51:57 +00002630 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002631 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00002632 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002633 Label* map_check() { return &map_check_; }
2634
2635 private:
2636 LInstanceOfKnownGlobal* instr_;
2637 Label map_check_;
2638 };
2639
2640 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002641 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002642
2643 Label done, false_result;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002644 Register object = ToRegister(instr->value());
2645 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002646 Register result = ToRegister(instr->result());
2647
2648 ASSERT(object.is(a0));
2649 ASSERT(result.is(v0));
2650
2651 // A Smi is not instance of anything.
2652 __ JumpIfSmi(object, &false_result);
2653
2654 // This is the inlined call site instanceof cache. The two occurences of the
2655 // hole value will be patched to the last map/result pair generated by the
2656 // instanceof stub.
2657 Label cache_miss;
2658 Register map = temp;
2659 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset));
2660
2661 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
2662 __ bind(deferred->map_check()); // Label for calculating code patching.
2663 // We use Factory::the_hole_value() on purpose instead of loading from the
2664 // root array to force relocation to be able to later patch with
2665 // the cached map.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002666 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002667 __ li(at, Operand(Handle<Object>(cell)));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002668 __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002669 __ Branch(&cache_miss, ne, map, Operand(at));
2670 // We use Factory::the_hole_value() on purpose instead of loading from the
2671 // root array to force relocation to be able to later patch
2672 // with true or false.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002673 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002674 __ Branch(&done);
2675
2676 // The inlined call site cache did not match. Check null and string before
2677 // calling the deferred code.
2678 __ bind(&cache_miss);
2679 // Null is not instance of anything.
2680 __ LoadRoot(temp, Heap::kNullValueRootIndex);
2681 __ Branch(&false_result, eq, object, Operand(temp));
2682
2683 // String values is not instance of anything.
2684 Condition cc = __ IsObjectStringType(object, temp, temp);
2685 __ Branch(&false_result, cc, temp, Operand(zero_reg));
2686
2687 // Go to the deferred code.
2688 __ Branch(deferred->entry());
2689
2690 __ bind(&false_result);
2691 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2692
2693 // Here result has either true or false. Deferred code also produces true or
2694 // false object.
2695 __ bind(deferred->exit());
2696 __ bind(&done);
2697}
2698
2699
erikcorry0ad885c2011-11-21 13:51:57 +00002700void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2701 Label* map_check) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002702 Register result = ToRegister(instr->result());
2703 ASSERT(result.is(v0));
2704
2705 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2706 flags = static_cast<InstanceofStub::Flags>(
2707 flags | InstanceofStub::kArgsInRegisters);
2708 flags = static_cast<InstanceofStub::Flags>(
2709 flags | InstanceofStub::kCallSiteInlineCheck);
2710 flags = static_cast<InstanceofStub::Flags>(
2711 flags | InstanceofStub::kReturnTrueFalseObject);
2712 InstanceofStub stub(flags);
2713
2714 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002715 LoadContextFromDeferred(instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002716
2717 // Get the temp register reserved by the instruction. This needs to be t0 as
2718 // its slot of the pushing of safepoint registers is used to communicate the
2719 // offset to the location of the map check.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002720 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002721 ASSERT(temp.is(t0));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002722 __ li(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002723 static const int kAdditionalDelta = 7;
2724 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2725 Label before_push_delta;
2726 __ bind(&before_push_delta);
2727 {
2728 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002729 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002730 __ StoreToSafepointRegisterSlot(temp, temp);
2731 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002732 CallCodeGeneric(stub.GetCode(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002733 RelocInfo::CODE_TARGET,
2734 instr,
2735 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00002736 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
erikcorry0ad885c2011-11-21 13:51:57 +00002737 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002738 // Put the result value into the result register slot and
2739 // restore all registers.
2740 __ StoreToSafepointRegisterSlot(result, result);
2741}
2742
2743
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002744void LCodeGen::DoCmpT(LCmpT* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002745 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002746 Token::Value op = instr->op();
2747
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002748 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002749 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2750 // On MIPS there is no need for a "no inlined smi code" marker (nop).
2751
2752 Condition condition = ComputeCompareCondition(op);
2753 // A minor optimization that relies on LoadRoot always emitting one
2754 // instruction.
2755 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002756 Label done, check;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002757 __ Branch(USE_DELAY_SLOT, &done, condition, v0, Operand(zero_reg));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002758 __ bind(&check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002759 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002760 ASSERT_EQ(1, masm()->InstructionsGeneratedSince(&check));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002761 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002762 __ bind(&done);
2763}
2764
2765
2766void LCodeGen::DoReturn(LReturn* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002767 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002768 // Push the return value on the stack as the parameter.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002769 // Runtime::TraceExit returns its parameter in v0. We're leaving the code
2770 // managed by the register allocator and tearing down the frame, it's
2771 // safe to write to the context register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002772 __ push(v0);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002773 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002774 __ CallRuntime(Runtime::kTraceExit, 1);
2775 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002776 if (info()->saves_caller_doubles()) {
machenbach@chromium.orgf9841892013-11-25 12:01:13 +00002777 RestoreCallerDoubles();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002778 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002779 int no_frame_start = -1;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002780 if (NeedsEagerFrame()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002781 __ mov(sp, fp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002782 no_frame_start = masm_->pc_offset();
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002783 __ Pop(ra, fp);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002784 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002785 if (instr->has_constant_parameter_count()) {
2786 int parameter_count = ToInteger32(instr->constant_parameter_count());
2787 int32_t sp_delta = (parameter_count + 1) * kPointerSize;
2788 if (sp_delta != 0) {
2789 __ Addu(sp, sp, Operand(sp_delta));
2790 }
2791 } else {
2792 Register reg = ToRegister(instr->parameter_count());
2793 // The argument count parameter is a smi
2794 __ SmiUntag(reg);
2795 __ sll(at, reg, kPointerSizeLog2);
2796 __ Addu(sp, sp, at);
2797 }
2798
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002799 __ Jump(ra);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002800
2801 if (no_frame_start != -1) {
2802 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2803 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002804}
2805
2806
2807void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2808 Register result = ToRegister(instr->result());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002809 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002810 __ lw(result, FieldMemOperand(at, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002811 if (instr->hydrogen()->RequiresHoleCheck()) {
2812 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2813 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2814 }
2815}
2816
2817
2818void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002819 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002820 ASSERT(ToRegister(instr->global_object()).is(a0));
2821 ASSERT(ToRegister(instr->result()).is(v0));
2822
2823 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002824 ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
2825 Handle<Code> ic = LoadIC::initialize_stub(isolate(), mode);
2826 CallCode(ic, RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002827}
2828
2829
2830void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002831 Register value = ToRegister(instr->value());
2832 Register cell = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002833
2834 // Load the cell.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002835 __ li(cell, Operand(instr->hydrogen()->cell().handle()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002836
2837 // If the cell we are storing to contains the hole it could have
2838 // been deleted from the property dictionary. In that case, we need
2839 // to update the property details in the property dictionary to mark
2840 // it as no longer deleted.
2841 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002842 // We use a temp to check the payload.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002843 Register payload = ToRegister(instr->temp());
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002844 __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002845 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002846 DeoptimizeIf(eq, instr->environment(), payload, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002847 }
2848
2849 // Store the value.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002850 __ sw(value, FieldMemOperand(cell, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002851 // Cells are always rescanned, so no write barrier here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002852}
2853
2854
2855void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002856 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002857 ASSERT(ToRegister(instr->global_object()).is(a1));
2858 ASSERT(ToRegister(instr->value()).is(a0));
2859
2860 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002861 Handle<Code> ic = StoreIC::initialize_stub(isolate(),
2862 instr->strict_mode_flag(),
2863 CONTEXTUAL);
2864 CallCode(ic, RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002865}
2866
2867
2868void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2869 Register context = ToRegister(instr->context());
2870 Register result = ToRegister(instr->result());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002871
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002872 __ lw(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002873 if (instr->hydrogen()->RequiresHoleCheck()) {
2874 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002875
2876 if (instr->hydrogen()->DeoptimizesOnHole()) {
2877 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2878 } else {
2879 Label is_not_hole;
2880 __ Branch(&is_not_hole, ne, result, Operand(at));
2881 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2882 __ bind(&is_not_hole);
2883 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002884 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002885}
2886
2887
2888void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2889 Register context = ToRegister(instr->context());
2890 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002891 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002892 MemOperand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002893
2894 Label skip_assignment;
2895
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002896 if (instr->hydrogen()->RequiresHoleCheck()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002897 __ lw(scratch, target);
2898 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002899
2900 if (instr->hydrogen()->DeoptimizesOnHole()) {
2901 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
2902 } else {
2903 __ Branch(&skip_assignment, ne, scratch, Operand(at));
2904 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002905 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002907 __ sw(value, target);
2908 if (instr->hydrogen()->NeedsWriteBarrier()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002909 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002910 instr->hydrogen()->value()->IsHeapObject()
2911 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002912 __ RecordWriteContextSlot(context,
2913 target.offset(),
2914 value,
2915 scratch0(),
danno@chromium.orgc99cd482013-03-21 15:26:42 +00002916 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002917 kSaveFPRegs,
2918 EMIT_REMEMBERED_SET,
2919 check_needed);
2920 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002921
2922 __ bind(&skip_assignment);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002923}
2924
2925
2926void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002927 HObjectAccess access = instr->hydrogen()->access();
2928 int offset = access.offset();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002929 Register object = ToRegister(instr->object());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002930
2931 if (access.IsExternalMemory()) {
2932 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002933 MemOperand operand = MemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002934 __ Load(result, operand, access.representation());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002935 return;
2936 }
2937
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002938 if (instr->hydrogen()->representation().IsDouble()) {
2939 DoubleRegister result = ToDoubleRegister(instr->result());
2940 __ ldc1(result, FieldMemOperand(object, offset));
2941 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002942 }
2943
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002944 Register result = ToRegister(instr->result());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002945 if (!access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002946 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00002947 object = result;
2948 }
2949 MemOperand operand = FieldMemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00002950 __ Load(result, operand, access.representation());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002951}
2952
2953
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002954void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00002955 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002956 ASSERT(ToRegister(instr->object()).is(a0));
2957 ASSERT(ToRegister(instr->result()).is(v0));
2958
2959 // Name is always in a2.
2960 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00002961 Handle<Code> ic = LoadIC::initialize_stub(isolate(), NOT_CONTEXTUAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002962 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2963}
2964
2965
2966void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2967 Register scratch = scratch0();
2968 Register function = ToRegister(instr->function());
2969 Register result = ToRegister(instr->result());
2970
2971 // Check that the function really is a function. Load map into the
2972 // result register.
2973 __ GetObjectType(function, result, scratch);
2974 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_FUNCTION_TYPE));
2975
2976 // Make sure that the function has an instance prototype.
2977 Label non_instance;
2978 __ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
2979 __ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
2980 __ Branch(&non_instance, ne, scratch, Operand(zero_reg));
2981
2982 // Get the prototype or initial map from the function.
2983 __ lw(result,
2984 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2985
2986 // Check that the function has a prototype or an initial map.
2987 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2988 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2989
2990 // If the function does not have an initial map, we're done.
2991 Label done;
2992 __ GetObjectType(result, scratch, scratch);
2993 __ Branch(&done, ne, scratch, Operand(MAP_TYPE));
2994
2995 // Get the prototype from the initial map.
2996 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
2997 __ Branch(&done);
2998
2999 // Non-instance prototype: Fetch prototype from constructor field
3000 // in initial map.
3001 __ bind(&non_instance);
3002 __ lw(result, FieldMemOperand(result, Map::kConstructorOffset));
3003
3004 // All done.
3005 __ bind(&done);
3006}
3007
3008
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003009void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
3010 Register result = ToRegister(instr->result());
3011 __ LoadRoot(result, instr->index());
3012}
3013
3014
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003015void LCodeGen::DoLoadExternalArrayPointer(
3016 LLoadExternalArrayPointer* instr) {
3017 Register to_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003018 Register from_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003019 __ lw(to_reg, FieldMemOperand(from_reg,
3020 ExternalArray::kExternalPointerOffset));
3021}
3022
3023
3024void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3025 Register arguments = ToRegister(instr->arguments());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003026 Register result = ToRegister(instr->result());
machenbach@chromium.org90dca012013-11-22 10:04:21 +00003027 // There are two words between the frame pointer and the last argument.
3028 // Subtracting from length accounts for one of them add one more.
3029 if (instr->length()->IsConstantOperand()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003030 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
machenbach@chromium.org90dca012013-11-22 10:04:21 +00003031 if (instr->index()->IsConstantOperand()) {
3032 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3033 int index = (const_length - const_index) + 1;
3034 __ lw(result, MemOperand(arguments, index * kPointerSize));
3035 } else {
3036 Register index = ToRegister(instr->index());
3037 __ li(at, Operand(const_length + 1));
3038 __ Subu(result, at, index);
3039 __ sll(at, result, kPointerSizeLog2);
3040 __ Addu(at, arguments, at);
3041 __ lw(result, MemOperand(at));
3042 }
3043 } else if (instr->index()->IsConstantOperand()) {
3044 Register length = ToRegister(instr->length());
3045 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3046 int loc = const_index - 1;
3047 if (loc != 0) {
3048 __ Subu(result, length, Operand(loc));
3049 __ sll(at, result, kPointerSizeLog2);
3050 __ Addu(at, arguments, at);
3051 __ lw(result, MemOperand(at));
3052 } else {
3053 __ sll(at, length, kPointerSizeLog2);
3054 __ Addu(at, arguments, at);
3055 __ lw(result, MemOperand(at));
3056 }
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003057 } else {
3058 Register length = ToRegister(instr->length());
3059 Register index = ToRegister(instr->index());
machenbach@chromium.org90dca012013-11-22 10:04:21 +00003060 __ Subu(result, length, index);
3061 __ Addu(result, result, 1);
3062 __ sll(at, result, kPointerSizeLog2);
3063 __ Addu(at, arguments, at);
3064 __ lw(result, MemOperand(at));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003065 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003066}
3067
3068
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003069void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
3070 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003071 Register key = no_reg;
3072 ElementsKind elements_kind = instr->elements_kind();
3073 bool key_is_constant = instr->key()->IsConstantOperand();
3074 int constant_key = 0;
3075 if (key_is_constant) {
3076 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
3077 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003078 Abort(kArrayIndexConstantValueTooBig);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003079 }
3080 } else {
3081 key = ToRegister(instr->key());
3082 }
danno@chromium.org129d3982012-07-25 15:01:47 +00003083 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003084 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00003085 ? (element_size_shift - kSmiTagSize) : element_size_shift;
3086 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003087
3088 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3089 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3090 FPURegister result = ToDoubleRegister(instr->result());
3091 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00003092 __ Addu(scratch0(), external_pointer, constant_key << element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003093 } else {
3094 __ sll(scratch0(), key, shift_size);
3095 __ Addu(scratch0(), scratch0(), external_pointer);
3096 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003097 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3098 __ lwc1(result, MemOperand(scratch0(), additional_offset));
3099 __ cvt_d_s(result, result);
3100 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
3101 __ ldc1(result, MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003102 }
3103 } else {
3104 Register result = ToRegister(instr->result());
danno@chromium.org129d3982012-07-25 15:01:47 +00003105 MemOperand mem_operand = PrepareKeyedOperand(
3106 key, external_pointer, key_is_constant, constant_key,
3107 element_size_shift, shift_size,
3108 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003109 switch (elements_kind) {
3110 case EXTERNAL_BYTE_ELEMENTS:
3111 __ lb(result, mem_operand);
3112 break;
3113 case EXTERNAL_PIXEL_ELEMENTS:
3114 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3115 __ lbu(result, mem_operand);
3116 break;
3117 case EXTERNAL_SHORT_ELEMENTS:
3118 __ lh(result, mem_operand);
3119 break;
3120 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3121 __ lhu(result, mem_operand);
3122 break;
3123 case EXTERNAL_INT_ELEMENTS:
3124 __ lw(result, mem_operand);
3125 break;
3126 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3127 __ lw(result, mem_operand);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003128 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3129 DeoptimizeIf(Ugreater_equal, instr->environment(),
3130 result, Operand(0x80000000));
3131 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003132 break;
3133 case EXTERNAL_FLOAT_ELEMENTS:
3134 case EXTERNAL_DOUBLE_ELEMENTS:
3135 case FAST_DOUBLE_ELEMENTS:
3136 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003137 case FAST_SMI_ELEMENTS:
3138 case FAST_HOLEY_DOUBLE_ELEMENTS:
3139 case FAST_HOLEY_ELEMENTS:
3140 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003141 case DICTIONARY_ELEMENTS:
3142 case NON_STRICT_ARGUMENTS_ELEMENTS:
3143 UNREACHABLE();
3144 break;
3145 }
3146 }
3147}
3148
3149
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003150void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3151 Register elements = ToRegister(instr->elements());
3152 bool key_is_constant = instr->key()->IsConstantOperand();
3153 Register key = no_reg;
3154 DoubleRegister result = ToDoubleRegister(instr->result());
3155 Register scratch = scratch0();
3156
3157 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003158
3159 int base_offset =
3160 FixedDoubleArray::kHeaderSize - kHeapObjectTag +
3161 (instr->additional_index() << element_size_shift);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003162 if (key_is_constant) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003163 int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003164 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00003165 Abort(kArrayIndexConstantValueTooBig);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003166 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003167 base_offset += constant_key << element_size_shift;
3168 }
3169 __ Addu(scratch, elements, Operand(base_offset));
3170
3171 if (!key_is_constant) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003172 key = ToRegister(instr->key());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003173 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
3174 ? (element_size_shift - kSmiTagSize) : element_size_shift;
3175 __ sll(at, key, shift_size);
3176 __ Addu(scratch, scratch, at);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003177 }
3178
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003179 __ ldc1(result, MemOperand(scratch));
3180
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003181 if (instr->hydrogen()->RequiresHoleCheck()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003182 __ lw(scratch, MemOperand(scratch, sizeof(kHoleNanLower32)));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003183 DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003184 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003185}
3186
3187
3188void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3189 Register elements = ToRegister(instr->elements());
3190 Register result = ToRegister(instr->result());
3191 Register scratch = scratch0();
3192 Register store_base = scratch;
3193 int offset = 0;
3194
3195 if (instr->key()->IsConstantOperand()) {
3196 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3197 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
3198 instr->additional_index());
3199 store_base = elements;
3200 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003201 Register key = ToRegister(instr->key());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003202 // Even though the HLoadKeyed instruction forces the input
3203 // representation for the key to be an integer, the input gets replaced
3204 // during bound check elimination with the index argument to the bounds
3205 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003206 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003207 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
3208 __ addu(scratch, elements, scratch);
3209 } else {
3210 __ sll(scratch, key, kPointerSizeLog2);
3211 __ addu(scratch, elements, scratch);
3212 }
3213 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
3214 }
3215 __ lw(result, FieldMemOperand(store_base, offset));
3216
3217 // Check for the hole value.
3218 if (instr->hydrogen()->RequiresHoleCheck()) {
3219 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003220 __ SmiTst(result, scratch);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003221 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3222 } else {
3223 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3224 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch));
3225 }
3226 }
3227}
3228
3229
3230void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3231 if (instr->is_external()) {
3232 DoLoadKeyedExternalArray(instr);
3233 } else if (instr->hydrogen()->representation().IsDouble()) {
3234 DoLoadKeyedFixedDoubleArray(instr);
3235 } else {
3236 DoLoadKeyedFixedArray(instr);
3237 }
3238}
3239
3240
3241MemOperand LCodeGen::PrepareKeyedOperand(Register key,
3242 Register base,
3243 bool key_is_constant,
3244 int constant_key,
3245 int element_size,
3246 int shift_size,
3247 int additional_index,
3248 int additional_offset) {
3249 if (additional_index != 0 && !key_is_constant) {
3250 additional_index *= 1 << (element_size - shift_size);
3251 __ Addu(scratch0(), key, Operand(additional_index));
3252 }
3253
3254 if (key_is_constant) {
3255 return MemOperand(base,
3256 (constant_key << element_size) + additional_offset);
3257 }
3258
3259 if (additional_index == 0) {
3260 if (shift_size >= 0) {
3261 __ sll(scratch0(), key, shift_size);
3262 __ Addu(scratch0(), base, scratch0());
3263 return MemOperand(scratch0());
3264 } else {
3265 ASSERT_EQ(-1, shift_size);
3266 __ srl(scratch0(), key, 1);
3267 __ Addu(scratch0(), base, scratch0());
3268 return MemOperand(scratch0());
3269 }
3270 }
3271
3272 if (shift_size >= 0) {
3273 __ sll(scratch0(), scratch0(), shift_size);
3274 __ Addu(scratch0(), base, scratch0());
3275 return MemOperand(scratch0());
3276 } else {
3277 ASSERT_EQ(-1, shift_size);
3278 __ srl(scratch0(), scratch0(), 1);
3279 __ Addu(scratch0(), base, scratch0());
3280 return MemOperand(scratch0());
3281 }
3282}
3283
3284
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003285void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003286 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003287 ASSERT(ToRegister(instr->object()).is(a1));
3288 ASSERT(ToRegister(instr->key()).is(a0));
3289
3290 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
3291 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3292}
3293
3294
3295void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3296 Register scratch = scratch0();
3297 Register temp = scratch1();
3298 Register result = ToRegister(instr->result());
3299
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003300 if (instr->hydrogen()->from_inlined()) {
3301 __ Subu(result, sp, 2 * kPointerSize);
3302 } else {
3303 // Check if the calling frame is an arguments adaptor frame.
3304 Label done, adapted;
3305 __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3306 __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
3307 __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003308
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003309 // Result is the frame pointer for the frame if not adapted and for the real
3310 // frame below the adaptor frame if adapted.
3311 __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
3312 __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
3313 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003314}
3315
3316
3317void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003318 Register elem = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003319 Register result = ToRegister(instr->result());
3320
3321 Label done;
3322
3323 // If no arguments adaptor frame the number of arguments is fixed.
3324 __ Addu(result, zero_reg, Operand(scope()->num_parameters()));
3325 __ Branch(&done, eq, fp, Operand(elem));
3326
3327 // Arguments adaptor frame present. Get argument length from there.
3328 __ lw(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3329 __ lw(result,
3330 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
3331 __ SmiUntag(result);
3332
3333 // Argument length is in result register.
3334 __ bind(&done);
3335}
3336
3337
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003338void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003339 Register receiver = ToRegister(instr->receiver());
3340 Register function = ToRegister(instr->function());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003341 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003342 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003343
3344 // If the receiver is null or undefined, we have to pass the global
3345 // object as a receiver to normal functions. Values have to be
3346 // passed unchanged to builtins and strict-mode functions.
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003347 Label global_object, result_in_receiver;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003348
3349 // Do not transform the receiver to object for strict mode
3350 // functions.
3351 __ lw(scratch,
3352 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
3353 __ lw(scratch,
3354 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
3355
3356 // Do not transform the receiver to object for builtins.
3357 int32_t strict_mode_function_mask =
3358 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
3359 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
3360 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask));
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003361 __ Branch(&result_in_receiver, ne, scratch, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003362
3363 // Normal function. Replace undefined or null with global receiver.
3364 __ LoadRoot(scratch, Heap::kNullValueRootIndex);
3365 __ Branch(&global_object, eq, receiver, Operand(scratch));
3366 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
3367 __ Branch(&global_object, eq, receiver, Operand(scratch));
3368
3369 // Deoptimize if the receiver is not a JS object.
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00003370 __ SmiTst(receiver, scratch);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003371 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3372
3373 __ GetObjectType(receiver, scratch, scratch);
3374 DeoptimizeIf(lt, instr->environment(),
3375 scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003376 __ Branch(&result_in_receiver);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003377
3378 __ bind(&global_object);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003379 __ lw(receiver, FieldMemOperand(function, JSFunction::kContextOffset));
3380 __ lw(receiver,
3381 ContextOperand(receiver, Context::GLOBAL_OBJECT_INDEX));
3382 __ lw(receiver,
3383 FieldMemOperand(receiver, GlobalObject::kGlobalReceiverOffset));
ulan@chromium.org0f13e742014-01-03 15:51:11 +00003384
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003385 if (result.is(receiver)) {
3386 __ bind(&result_in_receiver);
3387 } else {
3388 Label result_ok;
3389 __ Branch(&result_ok);
3390 __ bind(&result_in_receiver);
3391 __ mov(result, receiver);
3392 __ bind(&result_ok);
3393 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003394}
3395
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003396
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003397void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3398 Register receiver = ToRegister(instr->receiver());
3399 Register function = ToRegister(instr->function());
3400 Register length = ToRegister(instr->length());
3401 Register elements = ToRegister(instr->elements());
3402 Register scratch = scratch0();
3403 ASSERT(receiver.is(a0)); // Used for parameter count.
3404 ASSERT(function.is(a1)); // Required by InvokeFunction.
3405 ASSERT(ToRegister(instr->result()).is(v0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003406
3407 // Copy the arguments to this function possibly from the
3408 // adaptor frame below it.
3409 const uint32_t kArgumentsLimit = 1 * KB;
3410 DeoptimizeIf(hi, instr->environment(), length, Operand(kArgumentsLimit));
3411
3412 // Push the receiver and use the register to keep the original
3413 // number of arguments.
3414 __ push(receiver);
3415 __ Move(receiver, length);
3416 // The arguments are at a one pointer size offset from elements.
3417 __ Addu(elements, elements, Operand(1 * kPointerSize));
3418
3419 // Loop through the arguments pushing them onto the execution
3420 // stack.
3421 Label invoke, loop;
3422 // length is a small non-negative integer, due to the test above.
3423 __ Branch(USE_DELAY_SLOT, &invoke, eq, length, Operand(zero_reg));
3424 __ sll(scratch, length, 2);
3425 __ bind(&loop);
3426 __ Addu(scratch, elements, scratch);
3427 __ lw(scratch, MemOperand(scratch));
3428 __ push(scratch);
3429 __ Subu(length, length, Operand(1));
3430 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg));
3431 __ sll(scratch, length, 2);
3432
3433 __ bind(&invoke);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00003434 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003435 LPointerMap* pointers = instr->pointer_map();
erikcorry0ad885c2011-11-21 13:51:57 +00003436 SafepointGenerator safepoint_generator(
3437 this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003438 // The number of arguments is stored in receiver which is a0, as expected
3439 // by InvokeFunction.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003440 ParameterCount actual(receiver);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003441 __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003442}
3443
3444
3445void LCodeGen::DoPushArgument(LPushArgument* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003446 LOperand* argument = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003447 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
danno@chromium.org59400602013-08-13 17:09:37 +00003448 Abort(kDoPushArgumentNotImplementedForDoubleType);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003449 } else {
3450 Register argument_reg = EmitLoadRegister(argument, at);
3451 __ push(argument_reg);
3452 }
3453}
3454
3455
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003456void LCodeGen::DoDrop(LDrop* instr) {
3457 __ Drop(instr->count());
3458}
3459
3460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003461void LCodeGen::DoThisFunction(LThisFunction* instr) {
3462 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003463 __ lw(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003464}
3465
3466
3467void LCodeGen::DoContext(LContext* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003468 // If there is a non-return use, the context must be moved to a register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003469 Register result = ToRegister(instr->result());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003470 if (info()->IsOptimizing()) {
3471 __ lw(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
3472 } else {
3473 // If there is no frame, the context must be in cp.
3474 ASSERT(result.is(cp));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003475 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003476}
3477
3478
3479void LCodeGen::DoOuterContext(LOuterContext* instr) {
3480 Register context = ToRegister(instr->context());
3481 Register result = ToRegister(instr->result());
3482 __ lw(result,
3483 MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
3484}
3485
3486
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003487void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003488 ASSERT(ToRegister(instr->context()).is(cp));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003489 __ li(scratch0(), instr->hydrogen()->pairs());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003490 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags())));
3491 // The context is the first argument.
3492 __ Push(cp, scratch0(), scratch1());
3493 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3494}
3495
3496
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003497void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003498 Register context = ToRegister(instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003499 Register result = ToRegister(instr->result());
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003500 __ lw(result, ContextOperand(context, Context::GLOBAL_OBJECT_INDEX));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003501}
3502
3503
3504void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003505 Register global = ToRegister(instr->global_object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003506 Register result = ToRegister(instr->result());
3507 __ lw(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
3508}
3509
3510
3511void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003512 int formal_parameter_count,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003513 int arity,
3514 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003515 A1State a1_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003516 bool dont_adapt_arguments =
3517 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3518 bool can_invoke_directly =
3519 dont_adapt_arguments || formal_parameter_count == arity;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003520
3521 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003522
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003523 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003524 if (a1_state == A1_UNINITIALIZED) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003525 __ li(a1, function);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003526 }
3527
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003528 // Change context.
3529 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003530
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003531 // Set r0 to arguments count if adaption is not needed. Assumes that r0
3532 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003533 if (dont_adapt_arguments) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003534 __ li(a0, Operand(arity));
3535 }
3536
3537 // Invoke function.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003538 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
3539 __ Call(at);
3540
3541 // Set up deoptimization.
3542 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3543 } else {
3544 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3545 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003546 ParameterCount expected(formal_parameter_count);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003547 __ InvokeFunction(function, expected, count, CALL_FUNCTION, generator);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003548 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003549}
3550
3551
3552void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3553 ASSERT(ToRegister(instr->result()).is(v0));
3554 __ mov(a0, v0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003555 CallKnownFunction(instr->hydrogen()->function(),
3556 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003557 instr->arity(),
3558 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003559 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003560}
3561
3562
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003563void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003564 ASSERT(instr->context() != NULL);
3565 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003566 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003567 Register result = ToRegister(instr->result());
3568 Register scratch = scratch0();
3569
3570 // Deoptimize if not a heap number.
3571 __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
3572 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3573 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
3574
3575 Label done;
3576 Register exponent = scratch0();
3577 scratch = no_reg;
3578 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3579 // Check the sign of the argument. If the argument is positive, just
3580 // return it.
3581 __ Move(result, input);
3582 __ And(at, exponent, Operand(HeapNumber::kSignMask));
3583 __ Branch(&done, eq, at, Operand(zero_reg));
3584
3585 // Input is negative. Reverse its sign.
3586 // Preserve the value of all registers.
3587 {
3588 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3589
3590 // Registers were saved at the safepoint, so we can use
3591 // many scratch registers.
3592 Register tmp1 = input.is(a1) ? a0 : a1;
3593 Register tmp2 = input.is(a2) ? a0 : a2;
3594 Register tmp3 = input.is(a3) ? a0 : a3;
3595 Register tmp4 = input.is(t0) ? a0 : t0;
3596
3597 // exponent: floating point exponent value.
3598
3599 Label allocated, slow;
3600 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
3601 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
3602 __ Branch(&allocated);
3603
3604 // Slow case: Call the runtime system to do the number allocation.
3605 __ bind(&slow);
3606
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003607 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr,
3608 instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003609 // Set the pointer to the new heap number in tmp.
3610 if (!tmp1.is(v0))
3611 __ mov(tmp1, v0);
3612 // Restore input_reg after call to runtime.
3613 __ LoadFromSafepointRegisterSlot(input, input);
3614 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3615
3616 __ bind(&allocated);
3617 // exponent: floating point exponent value.
3618 // tmp1: allocated heap number.
3619 __ And(exponent, exponent, Operand(~HeapNumber::kSignMask));
3620 __ sw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
3621 __ lw(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
3622 __ sw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
3623
3624 __ StoreToSafepointRegisterSlot(tmp1, result);
3625 }
3626
3627 __ bind(&done);
3628}
3629
3630
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003631void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003632 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003633 Register result = ToRegister(instr->result());
3634 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
3635 Label done;
3636 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg));
3637 __ mov(result, input);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003638 __ subu(result, zero_reg, input);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003639 // Overflow if result is still negative, i.e. 0x80000000.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003640 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
3641 __ bind(&done);
3642}
3643
3644
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003645void LCodeGen::DoMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003646 // Class for deferred case.
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003647 class DeferredMathAbsTaggedHeapNumber V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003648 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003649 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003650 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003651 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003652 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3653 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00003654 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003655 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003656 LMathAbs* instr_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003657 };
3658
3659 Representation r = instr->hydrogen()->value()->representation();
3660 if (r.IsDouble()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003661 FPURegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003662 FPURegister result = ToDoubleRegister(instr->result());
3663 __ abs_d(result, input);
danno@chromium.org59400602013-08-13 17:09:37 +00003664 } else if (r.IsSmiOrInteger32()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003665 EmitIntegerMathAbs(instr);
3666 } else {
3667 // Representation is tagged.
3668 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003669 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003670 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003671 // Smi check.
3672 __ JumpIfNotSmi(input, deferred->entry());
3673 // If smi, handle it directly.
3674 EmitIntegerMathAbs(instr);
3675 __ bind(deferred->exit());
3676 }
3677}
3678
3679
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003680void LCodeGen::DoMathFloor(LMathFloor* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003681 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003682 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003683 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003684 Register except_flag = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003685
3686 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003687 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003688 input,
3689 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003690 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003691 except_flag);
3692
3693 // Deopt if the operation did not succeed.
3694 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3695
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003696 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3697 // Test for -0.
3698 Label done;
3699 __ Branch(&done, ne, result, Operand(zero_reg));
3700 __ mfc1(scratch1, input.high());
3701 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
3702 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
3703 __ bind(&done);
3704 }
3705}
3706
3707
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003708void LCodeGen::DoMathRound(LMathRound* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003709 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003710 Register result = ToRegister(instr->result());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003711 DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003712 Register scratch = scratch0();
3713 Label done, check_sign_on_zero;
3714
3715 // Extract exponent bits.
3716 __ mfc1(result, input.high());
3717 __ Ext(scratch,
3718 result,
3719 HeapNumber::kExponentShift,
3720 HeapNumber::kExponentBits);
3721
3722 // If the number is in ]-0.5, +0.5[, the result is +/- 0.
3723 Label skip1;
3724 __ Branch(&skip1, gt, scratch, Operand(HeapNumber::kExponentBias - 2));
3725 __ mov(result, zero_reg);
3726 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3727 __ Branch(&check_sign_on_zero);
3728 } else {
3729 __ Branch(&done);
3730 }
3731 __ bind(&skip1);
3732
3733 // The following conversion will not work with numbers
3734 // outside of ]-2^32, 2^32[.
3735 DeoptimizeIf(ge, instr->environment(), scratch,
3736 Operand(HeapNumber::kExponentBias + 32));
3737
3738 // Save the original sign for later comparison.
3739 __ And(scratch, result, Operand(HeapNumber::kSignMask));
3740
3741 __ Move(double_scratch0(), 0.5);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003742 __ add_d(double_scratch0(), input, double_scratch0());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003743
3744 // Check sign of the result: if the sign changed, the input
3745 // value was in ]0.5, 0[ and the result should be -0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003746 __ mfc1(result, double_scratch0().high());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003747 __ Xor(result, result, Operand(scratch));
3748 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3749 // ARM uses 'mi' here, which is 'lt'
3750 DeoptimizeIf(lt, instr->environment(), result,
3751 Operand(zero_reg));
3752 } else {
3753 Label skip2;
3754 // ARM uses 'mi' here, which is 'lt'
3755 // Negating it results in 'ge'
3756 __ Branch(&skip2, ge, result, Operand(zero_reg));
3757 __ mov(result, zero_reg);
3758 __ Branch(&done);
3759 __ bind(&skip2);
3760 }
3761
3762 Register except_flag = scratch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003763 __ EmitFPUTruncate(kRoundToMinusInf,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003764 result,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003765 double_scratch0(),
3766 at,
3767 double_scratch1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003768 except_flag);
3769
3770 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3771
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003772 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3773 // Test for -0.
3774 __ Branch(&done, ne, result, Operand(zero_reg));
3775 __ bind(&check_sign_on_zero);
3776 __ mfc1(scratch, input.high());
3777 __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
3778 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3779 }
3780 __ bind(&done);
3781}
3782
3783
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003784void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003785 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003786 DoubleRegister result = ToDoubleRegister(instr->result());
3787 __ sqrt_d(result, input);
3788}
3789
3790
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003791void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003792 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003793 DoubleRegister result = ToDoubleRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003794 DoubleRegister temp = ToDoubleRegister(instr->temp());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003795
3796 ASSERT(!input.is(result));
3797
3798 // Note that according to ECMA-262 15.8.2.13:
3799 // Math.pow(-Infinity, 0.5) == Infinity
3800 // Math.sqrt(-Infinity) == NaN
3801 Label done;
3802 __ Move(temp, -V8_INFINITY);
3803 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
3804 // Set up Infinity in the delay slot.
3805 // result is overwritten if the branch is not taken.
3806 __ neg_d(result, temp);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003807
3808 // Add +0 to convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003809 __ add_d(result, input, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003810 __ sqrt_d(result, result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003811 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003812}
3813
3814
3815void LCodeGen::DoPower(LPower* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003816 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003817 // Having marked this as a call, we can use any registers.
3818 // Just make sure that the input/output registers are the expected ones.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003819 ASSERT(!instr->right()->IsDoubleRegister() ||
3820 ToDoubleRegister(instr->right()).is(f4));
3821 ASSERT(!instr->right()->IsRegister() ||
3822 ToRegister(instr->right()).is(a2));
3823 ASSERT(ToDoubleRegister(instr->left()).is(f2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003824 ASSERT(ToDoubleRegister(instr->result()).is(f0));
3825
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003826 if (exponent_type.IsSmi()) {
3827 MathPowStub stub(MathPowStub::TAGGED);
3828 __ CallStub(&stub);
3829 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003830 Label no_deopt;
3831 __ JumpIfSmi(a2, &no_deopt);
3832 __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset));
3833 DeoptimizeIf(ne, instr->environment(), t3, Operand(at));
3834 __ bind(&no_deopt);
3835 MathPowStub stub(MathPowStub::TAGGED);
3836 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003837 } else if (exponent_type.IsInteger32()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003838 MathPowStub stub(MathPowStub::INTEGER);
3839 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003840 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003841 ASSERT(exponent_type.IsDouble());
3842 MathPowStub stub(MathPowStub::DOUBLE);
3843 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003844 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003845}
3846
3847
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003848void LCodeGen::DoMathExp(LMathExp* instr) {
3849 DoubleRegister input = ToDoubleRegister(instr->value());
3850 DoubleRegister result = ToDoubleRegister(instr->result());
3851 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
3852 DoubleRegister double_scratch2 = double_scratch0();
3853 Register temp1 = ToRegister(instr->temp1());
3854 Register temp2 = ToRegister(instr->temp2());
3855
3856 MathExpGenerator::EmitMathExp(
3857 masm(), input, result, double_scratch1, double_scratch2,
3858 temp1, temp2, scratch0());
3859}
3860
3861
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003862void LCodeGen::DoMathLog(LMathLog* instr) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003863 __ PrepareCallCFunction(0, 1, scratch0());
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00003864 __ MovToFloatParameter(ToDoubleRegister(instr->value()));
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003865 __ CallCFunction(ExternalReference::math_log_double_function(isolate()),
3866 0, 1);
machenbach@chromium.org4ddd2f12014-01-14 08:13:44 +00003867 __ MovFromFloatResult(ToDoubleRegister(instr->result()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003868}
3869
3870
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003871void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003872 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003873 ASSERT(ToRegister(instr->function()).is(a1));
3874 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003875
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003876 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3877 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003878 LPointerMap* pointers = instr->pointer_map();
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003879 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3880 ParameterCount count(instr->arity());
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003881 __ InvokeFunction(a1, count, CALL_FUNCTION, generator);
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003882 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003883 CallKnownFunction(known_function,
3884 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003885 instr->arity(),
3886 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003887 A1_CONTAINS_TARGET);
3888 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003889}
3890
3891
3892void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003893 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003894 ASSERT(ToRegister(instr->result()).is(v0));
3895
3896 int arity = instr->arity();
3897 Handle<Code> ic =
3898 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
3899 CallCode(ic, RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003900}
3901
3902
3903void LCodeGen::DoCallNamed(LCallNamed* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003904 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003905 ASSERT(ToRegister(instr->result()).is(v0));
3906
3907 int arity = instr->arity();
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003908 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003909 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00003910 CallCode(ic, RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003911}
3912
3913
3914void LCodeGen::DoCallFunction(LCallFunction* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003915 ASSERT(ToRegister(instr->context()).is(cp));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003916 ASSERT(ToRegister(instr->function()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003917 ASSERT(ToRegister(instr->result()).is(v0));
3918
3919 int arity = instr->arity();
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00003920 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
machenbach@chromium.orgea468882013-11-18 08:53:19 +00003921 if (instr->hydrogen()->IsTailCall()) {
3922 if (NeedsEagerFrame()) __ mov(sp, fp);
3923 __ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
3924 } else {
3925 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
3926 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003927}
3928
3929
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003930void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3931 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003932 CallKnownFunction(instr->hydrogen()->target(),
3933 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003934 instr->arity(),
3935 instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003936 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003937}
3938
3939
3940void LCodeGen::DoCallNew(LCallNew* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003941 ASSERT(ToRegister(instr->context()).is(cp));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003942 ASSERT(ToRegister(instr->constructor()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003943 ASSERT(ToRegister(instr->result()).is(v0));
3944
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003945 __ li(a0, Operand(instr->arity()));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003946 // No cell in a2 for construct type feedback in optimized code
3947 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
3948 __ li(a2, Operand(undefined_value));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003949 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003950 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003951}
3952
3953
ulan@chromium.org750145a2013-03-07 15:14:13 +00003954void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003955 ASSERT(ToRegister(instr->context()).is(cp));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003956 ASSERT(ToRegister(instr->constructor()).is(a1));
3957 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003958
3959 __ li(a0, Operand(instr->arity()));
3960 __ li(a2, Operand(instr->hydrogen()->property_cell()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003961 ElementsKind kind = instr->hydrogen()->elements_kind();
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00003962 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00003963 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00003964 ? DISABLE_ALLOCATION_SITES
3965 : DONT_OVERRIDE;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003966
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003967 if (instr->arity() == 0) {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003968 ArrayNoArgumentConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003969 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3970 } else if (instr->arity() == 1) {
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003971 Label done;
3972 if (IsFastPackedElementsKind(kind)) {
3973 Label packed_case;
3974 // We might need a change here,
3975 // look at the first argument.
3976 __ lw(t1, MemOperand(sp, 0));
3977 __ Branch(&packed_case, eq, t1, Operand(zero_reg));
3978
3979 ElementsKind holey_kind = GetHoleyElementsKind(kind);
machenbach@chromium.org03453962014-01-10 14:16:31 +00003980 ArraySingleArgumentConstructorStub stub(holey_kind, override_mode);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003981 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3982 __ jmp(&done);
3983 __ bind(&packed_case);
3984 }
3985
machenbach@chromium.org03453962014-01-10 14:16:31 +00003986 ArraySingleArgumentConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003987 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00003988 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003989 } else {
machenbach@chromium.org03453962014-01-10 14:16:31 +00003990 ArrayNArgumentsConstructorStub stub(kind, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003991 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3992 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00003993}
3994
3995
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003996void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
3997 CallRuntime(instr->function(), instr->arity(), instr);
3998}
3999
4000
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004001void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
4002 Register function = ToRegister(instr->function());
4003 Register code_object = ToRegister(instr->code_object());
4004 __ Addu(code_object, code_object,
4005 Operand(Code::kHeaderSize - kHeapObjectTag));
4006 __ sw(code_object,
4007 FieldMemOperand(function, JSFunction::kCodeEntryOffset));
4008}
4009
4010
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00004011void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4012 Register result = ToRegister(instr->result());
4013 Register base = ToRegister(instr->base_object());
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004014 if (instr->offset()->IsConstantOperand()) {
4015 LConstantOperand* offset = LConstantOperand::cast(instr->offset());
4016 __ Addu(result, base, Operand(ToInteger32(offset)));
4017 } else {
4018 Register offset = ToRegister(instr->offset());
4019 __ Addu(result, base, offset);
4020 }
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00004021}
4022
4023
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004024void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004025 Representation representation = instr->representation();
4026
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004027 Register object = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004028 Register scratch = scratch0();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004029 HObjectAccess access = instr->hydrogen()->access();
4030 int offset = access.offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004031
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004032 if (access.IsExternalMemory()) {
4033 Register value = ToRegister(instr->value());
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004034 MemOperand operand = MemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004035 __ Store(value, operand, representation);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004036 return;
4037 }
4038
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004039 Handle<Map> transition = instr->transition();
4040
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004041 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004042 Register value = ToRegister(instr->value());
4043 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00004044 __ SmiTst(value, scratch);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004045 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
4046 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004047 } else if (FLAG_track_double_fields && representation.IsDouble()) {
4048 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004049 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004050 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4051 DoubleRegister value = ToDoubleRegister(instr->value());
4052 __ sdc1(value, FieldMemOperand(object, offset));
4053 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00004054 }
4055
danno@chromium.orgf005df62013-04-30 16:36:45 +00004056 if (!transition.is_null()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004057 __ li(scratch, Operand(transition));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004058 __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +00004059 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004060 Register temp = ToRegister(instr->temp());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004061 // Update the write barrier for the map field.
4062 __ RecordWriteField(object,
4063 HeapObject::kMapOffset,
4064 scratch,
4065 temp,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004066 GetRAState(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004067 kSaveFPRegs,
4068 OMIT_REMEMBERED_SET,
4069 OMIT_SMI_CHECK);
4070 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004071 }
4072
4073 // Do the store.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004074 Register value = ToRegister(instr->value());
4075 ASSERT(!object.is(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004076 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004077 instr->hydrogen()->value()->IsHeapObject()
4078 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004079 if (access.IsInobject()) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004080 MemOperand operand = FieldMemOperand(object, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004081 __ Store(value, operand, representation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004082 if (instr->hydrogen()->NeedsWriteBarrier()) {
4083 // Update the write barrier for the object for in-object properties.
4084 __ RecordWriteField(object,
4085 offset,
4086 value,
4087 scratch,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004088 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004089 kSaveFPRegs,
4090 EMIT_REMEMBERED_SET,
4091 check_needed);
4092 }
4093 } else {
4094 __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00004095 MemOperand operand = FieldMemOperand(scratch, offset);
machenbach@chromium.org935a7792013-11-12 09:05:18 +00004096 __ Store(value, operand, representation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004097 if (instr->hydrogen()->NeedsWriteBarrier()) {
4098 // Update the write barrier for the properties array.
4099 // object is used as a scratch register.
4100 __ RecordWriteField(scratch,
4101 offset,
4102 value,
4103 object,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004104 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004105 kSaveFPRegs,
4106 EMIT_REMEMBERED_SET,
4107 check_needed);
4108 }
4109 }
4110}
4111
4112
4113void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004114 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004115 ASSERT(ToRegister(instr->object()).is(a1));
4116 ASSERT(ToRegister(instr->value()).is(a0));
4117
4118 // Name is always in a2.
4119 __ li(a2, Operand(instr->name()));
ulan@chromium.org9cbaabd2014-01-08 10:55:36 +00004120 Handle<Code> ic = StoreIC::initialize_stub(isolate(),
4121 instr->strict_mode_flag(),
4122 NOT_CONTEXTUAL);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004123 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4124}
4125
4126
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004127void LCodeGen::ApplyCheckIf(Condition condition,
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004128 LBoundsCheck* check,
4129 Register src1,
4130 const Operand& src2) {
4131 if (FLAG_debug_code && check->hydrogen()->skip_check()) {
4132 Label done;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004133 __ Branch(&done, NegateCondition(condition), src1, src2);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004134 __ stop("eliminated bounds check failed");
4135 __ bind(&done);
4136 } else {
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004137 DeoptimizeIf(condition, check->environment(), src1, src2);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004138 }
4139}
4140
4141
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004142void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004143 if (instr->hydrogen()->skip_check()) return;
4144
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004145 Condition condition = instr->hydrogen()->allow_equality() ? hi : hs;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004146 if (instr->index()->IsConstantOperand()) {
4147 int constant_index =
4148 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004149 if (instr->hydrogen()->length()->representation().IsSmi()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004150 __ li(at, Operand(Smi::FromInt(constant_index)));
4151 } else {
4152 __ li(at, Operand(constant_index));
4153 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004154 ApplyCheckIf(condition,
4155 instr,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004156 at,
4157 Operand(ToRegister(instr->length())));
4158 } else {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004159 ApplyCheckIf(condition,
4160 instr,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004161 ToRegister(instr->index()),
4162 Operand(ToRegister(instr->length())));
4163 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004164}
4165
4166
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004167void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4168 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004169 Register key = no_reg;
4170 ElementsKind elements_kind = instr->elements_kind();
4171 bool key_is_constant = instr->key()->IsConstantOperand();
4172 int constant_key = 0;
4173 if (key_is_constant) {
4174 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4175 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00004176 Abort(kArrayIndexConstantValueTooBig);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004177 }
4178 } else {
4179 key = ToRegister(instr->key());
4180 }
danno@chromium.org129d3982012-07-25 15:01:47 +00004181 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004182 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00004183 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4184 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004185
4186 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
4187 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004188 Register address = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004189 FPURegister value(ToDoubleRegister(instr->value()));
4190 if (key_is_constant) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004191 if (constant_key != 0) {
4192 __ Addu(address, external_pointer,
4193 Operand(constant_key << element_size_shift));
4194 } else {
4195 address = external_pointer;
4196 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004197 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004198 __ sll(address, key, shift_size);
4199 __ Addu(address, external_pointer, address);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004200 }
4201
4202 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4203 __ cvt_s_d(double_scratch0(), value);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004204 __ swc1(double_scratch0(), MemOperand(address, additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004205 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004206 __ sdc1(value, MemOperand(address, additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004207 }
4208 } else {
4209 Register value(ToRegister(instr->value()));
danno@chromium.org129d3982012-07-25 15:01:47 +00004210 MemOperand mem_operand = PrepareKeyedOperand(
4211 key, external_pointer, key_is_constant, constant_key,
4212 element_size_shift, shift_size,
4213 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004214 switch (elements_kind) {
4215 case EXTERNAL_PIXEL_ELEMENTS:
4216 case EXTERNAL_BYTE_ELEMENTS:
4217 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4218 __ sb(value, mem_operand);
4219 break;
4220 case EXTERNAL_SHORT_ELEMENTS:
4221 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4222 __ sh(value, mem_operand);
4223 break;
4224 case EXTERNAL_INT_ELEMENTS:
4225 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4226 __ sw(value, mem_operand);
4227 break;
4228 case EXTERNAL_FLOAT_ELEMENTS:
4229 case EXTERNAL_DOUBLE_ELEMENTS:
4230 case FAST_DOUBLE_ELEMENTS:
4231 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004232 case FAST_SMI_ELEMENTS:
4233 case FAST_HOLEY_DOUBLE_ELEMENTS:
4234 case FAST_HOLEY_ELEMENTS:
4235 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004236 case DICTIONARY_ELEMENTS:
4237 case NON_STRICT_ARGUMENTS_ELEMENTS:
4238 UNREACHABLE();
4239 break;
4240 }
4241 }
4242}
4243
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004244
4245void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4246 DoubleRegister value = ToDoubleRegister(instr->value());
4247 Register elements = ToRegister(instr->elements());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004248 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004249 DoubleRegister double_scratch = double_scratch0();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004250 bool key_is_constant = instr->key()->IsConstantOperand();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004251 Label not_nan, done;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004252
4253 // Calculate the effective address of the slot in the array to store the
4254 // double value.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004255 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004256 if (key_is_constant) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004257 int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004258 if (constant_key & 0xF0000000) {
danno@chromium.org59400602013-08-13 17:09:37 +00004259 Abort(kArrayIndexConstantValueTooBig);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004260 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004261 __ Addu(scratch, elements,
4262 Operand((constant_key << element_size_shift) +
4263 FixedDoubleArray::kHeaderSize - kHeapObjectTag));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004264 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004265 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
4266 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4267 __ Addu(scratch, elements,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004268 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004269 __ sll(at, ToRegister(instr->key()), shift_size);
4270 __ Addu(scratch, scratch, at);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004271 }
4272
4273 if (instr->NeedsCanonicalization()) {
4274 Label is_nan;
4275 // Check for NaN. All NaNs must be canonicalized.
4276 __ BranchF(NULL, &is_nan, eq, value, value);
4277 __ Branch(&not_nan);
4278
4279 // Only load canonical NaN if the comparison above set the overflow.
4280 __ bind(&is_nan);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004281 __ Move(double_scratch,
4282 FixedDoubleArray::canonical_not_the_hole_nan_as_double());
4283 __ sdc1(double_scratch, MemOperand(scratch, instr->additional_index() <<
4284 element_size_shift));
4285 __ Branch(&done);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004286 }
4287
4288 __ bind(&not_nan);
4289 __ sdc1(value, MemOperand(scratch, instr->additional_index() <<
4290 element_size_shift));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004291 __ bind(&done);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004292}
4293
4294
4295void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4296 Register value = ToRegister(instr->value());
4297 Register elements = ToRegister(instr->elements());
4298 Register key = instr->key()->IsRegister() ? ToRegister(instr->key())
4299 : no_reg;
4300 Register scratch = scratch0();
4301 Register store_base = scratch;
4302 int offset = 0;
4303
4304 // Do the store.
4305 if (instr->key()->IsConstantOperand()) {
4306 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4307 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
4308 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
4309 instr->additional_index());
4310 store_base = elements;
4311 } else {
4312 // Even though the HLoadKeyed instruction forces the input
4313 // representation for the key to be an integer, the input gets replaced
4314 // during bound check elimination with the index argument to the bounds
4315 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004316 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004317 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
4318 __ addu(scratch, elements, scratch);
4319 } else {
4320 __ sll(scratch, key, kPointerSizeLog2);
4321 __ addu(scratch, elements, scratch);
4322 }
4323 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
4324 }
4325 __ sw(value, FieldMemOperand(store_base, offset));
4326
4327 if (instr->hydrogen()->NeedsWriteBarrier()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004328 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004329 instr->hydrogen()->value()->IsHeapObject()
4330 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004331 // Compute address of modified element and store it into key register.
4332 __ Addu(key, store_base, Operand(offset - kHeapObjectTag));
4333 __ RecordWrite(elements,
4334 key,
4335 value,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004336 GetRAState(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004337 kSaveFPRegs,
4338 EMIT_REMEMBERED_SET,
4339 check_needed);
4340 }
4341}
4342
4343
4344void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4345 // By cases: external, fast double
4346 if (instr->is_external()) {
4347 DoStoreKeyedExternalArray(instr);
4348 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4349 DoStoreKeyedFixedDoubleArray(instr);
4350 } else {
4351 DoStoreKeyedFixedArray(instr);
4352 }
4353}
4354
4355
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004356void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004357 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004358 ASSERT(ToRegister(instr->object()).is(a2));
4359 ASSERT(ToRegister(instr->key()).is(a1));
4360 ASSERT(ToRegister(instr->value()).is(a0));
4361
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004362 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004363 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4364 : isolate()->builtins()->KeyedStoreIC_Initialize();
4365 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4366}
4367
4368
4369void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4370 Register object_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004371 Register scratch = scratch0();
4372
4373 Handle<Map> from_map = instr->original_map();
4374 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004375 ElementsKind from_kind = instr->from_kind();
4376 ElementsKind to_kind = instr->to_kind();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004377
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004378 Label not_applicable;
4379 __ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4380 __ Branch(&not_applicable, ne, scratch, Operand(from_map));
4381
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004382 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004383 Register new_map_reg = ToRegister(instr->new_map_temp());
4384 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004385 __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4386 // Write barrier.
4387 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004388 scratch, GetRAState(), kDontSaveFPRegs);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00004389 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004390 ASSERT(ToRegister(instr->context()).is(cp));
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004391 PushSafepointRegistersScope scope(
4392 this, Safepoint::kWithRegistersAndDoubles);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004393 __ mov(a0, object_reg);
4394 __ li(a1, Operand(to_map));
4395 TransitionElementsKindStub stub(from_kind, to_kind);
4396 __ CallStub(&stub);
danno@chromium.orgc00ec2b2013-08-14 17:13:49 +00004397 RecordSafepointWithRegistersAndDoubles(
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004398 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004399 }
4400 __ bind(&not_applicable);
4401}
4402
4403
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004404void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4405 Register object = ToRegister(instr->object());
4406 Register temp = ToRegister(instr->temp());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004407 Label no_memento_found;
4408 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found,
4409 ne, &no_memento_found);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004410 DeoptimizeIf(al, instr->environment());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00004411 __ bind(&no_memento_found);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004412}
4413
4414
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004415void LCodeGen::DoStringAdd(LStringAdd* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004416 ASSERT(ToRegister(instr->context()).is(cp));
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00004417 if (FLAG_new_string_add) {
4418 ASSERT(ToRegister(instr->left()).is(a1));
4419 ASSERT(ToRegister(instr->right()).is(a0));
4420 NewStringAddStub stub(instr->hydrogen()->flags(),
4421 isolate()->heap()->GetPretenureMode());
4422 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4423 } else {
4424 __ push(ToRegister(instr->left()));
4425 __ push(ToRegister(instr->right()));
4426 StringAddStub stub(instr->hydrogen()->flags());
4427 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
4428 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004429}
4430
4431
4432void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004433 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004434 public:
4435 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4436 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004437 virtual void Generate() V8_OVERRIDE {
4438 codegen()->DoDeferredStringCharCodeAt(instr_);
4439 }
4440 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004441 private:
4442 LStringCharCodeAt* instr_;
4443 };
4444
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004445 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004446 new(zone()) DeferredStringCharCodeAt(this, instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004447 StringCharLoadGenerator::Generate(masm(),
4448 ToRegister(instr->string()),
4449 ToRegister(instr->index()),
4450 ToRegister(instr->result()),
4451 deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004452 __ bind(deferred->exit());
4453}
4454
4455
4456void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4457 Register string = ToRegister(instr->string());
4458 Register result = ToRegister(instr->result());
4459 Register scratch = scratch0();
4460
4461 // TODO(3095996): Get rid of this. For now, we need to make the
4462 // result register contain a valid pointer because it is already
4463 // contained in the register pointer map.
4464 __ mov(result, zero_reg);
4465
4466 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4467 __ push(string);
4468 // Push the index as a smi. This is safe because of the checks in
4469 // DoStringCharCodeAt above.
4470 if (instr->index()->IsConstantOperand()) {
4471 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4472 __ Addu(scratch, zero_reg, Operand(Smi::FromInt(const_index)));
4473 __ push(scratch);
4474 } else {
4475 Register index = ToRegister(instr->index());
4476 __ SmiTag(index);
4477 __ push(index);
4478 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004479 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr,
4480 instr->context());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004481 __ AssertSmi(v0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004482 __ SmiUntag(v0);
4483 __ StoreToSafepointRegisterSlot(v0, result);
4484}
4485
4486
4487void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004488 class DeferredStringCharFromCode V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004489 public:
4490 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4491 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004492 virtual void Generate() V8_OVERRIDE {
4493 codegen()->DoDeferredStringCharFromCode(instr_);
4494 }
4495 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004496 private:
4497 LStringCharFromCode* instr_;
4498 };
4499
4500 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004501 new(zone()) DeferredStringCharFromCode(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004502
4503 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4504 Register char_code = ToRegister(instr->char_code());
4505 Register result = ToRegister(instr->result());
4506 Register scratch = scratch0();
4507 ASSERT(!char_code.is(result));
4508
4509 __ Branch(deferred->entry(), hi,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004510 char_code, Operand(String::kMaxOneByteCharCode));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004511 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4512 __ sll(scratch, char_code, kPointerSizeLog2);
4513 __ Addu(result, result, scratch);
4514 __ lw(result, FieldMemOperand(result, FixedArray::kHeaderSize));
4515 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
4516 __ Branch(deferred->entry(), eq, result, Operand(scratch));
4517 __ bind(deferred->exit());
4518}
4519
4520
4521void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4522 Register char_code = ToRegister(instr->char_code());
4523 Register result = ToRegister(instr->result());
4524
4525 // TODO(3095996): Get rid of this. For now, we need to make the
4526 // result register contain a valid pointer because it is already
4527 // contained in the register pointer map.
4528 __ mov(result, zero_reg);
4529
4530 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4531 __ SmiTag(char_code);
4532 __ push(char_code);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004533 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004534 __ StoreToSafepointRegisterSlot(v0, result);
4535}
4536
4537
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004538void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004539 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004540 ASSERT(input->IsRegister() || input->IsStackSlot());
4541 LOperand* output = instr->result();
4542 ASSERT(output->IsDoubleRegister());
4543 FPURegister single_scratch = double_scratch0().low();
4544 if (input->IsStackSlot()) {
4545 Register scratch = scratch0();
4546 __ lw(scratch, ToMemOperand(input));
4547 __ mtc1(scratch, single_scratch);
4548 } else {
4549 __ mtc1(ToRegister(input), single_scratch);
4550 }
4551 __ cvt_d_w(ToDoubleRegister(output), single_scratch);
4552}
4553
4554
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004555void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4556 LOperand* input = instr->value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004557 LOperand* output = instr->result();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004558 Register scratch = scratch0();
4559
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004560 ASSERT(output->IsRegister());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004561 if (!instr->hydrogen()->value()->HasRange() ||
4562 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004563 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004564 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00004565 } else {
4566 __ SmiTag(ToRegister(output), ToRegister(input));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004567 }
4568}
4569
4570
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004571void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004572 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004573 LOperand* output = instr->result();
4574
4575 FPURegister dbl_scratch = double_scratch0();
4576 __ mtc1(ToRegister(input), dbl_scratch);
4577 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22);
4578}
4579
4580
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004581void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
4582 LOperand* input = instr->value();
4583 LOperand* output = instr->result();
4584 if (!instr->hydrogen()->value()->HasRange() ||
4585 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4586 Register scratch = scratch0();
4587 __ And(scratch, ToRegister(input), Operand(0xc0000000));
4588 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4589 }
4590 __ SmiTag(ToRegister(output), ToRegister(input));
4591}
4592
4593
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004594void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004595 class DeferredNumberTagI V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004596 public:
4597 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4598 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004599 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004600 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004601 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004602 SIGNED_INT32);
4603 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004604 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004605 private:
4606 LNumberTagI* instr_;
4607 };
4608
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004609 Register src = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004610 Register dst = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004611 Register overflow = scratch0();
4612
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004613 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004614 __ SmiTagCheckOverflow(dst, src, overflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004615 __ BranchOnOverflow(deferred->entry(), overflow);
4616 __ bind(deferred->exit());
4617}
4618
4619
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004620void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004621 class DeferredNumberTagU V8_FINAL : public LDeferredCode {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004622 public:
4623 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4624 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004625 virtual void Generate() V8_OVERRIDE {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004626 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004627 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004628 UNSIGNED_INT32);
4629 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004630 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004631 private:
4632 LNumberTagU* instr_;
4633 };
4634
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004635 Register input = ToRegister(instr->value());
4636 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004637
4638 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
machenbach@chromium.org8a58f642013-12-02 10:46:30 +00004639 __ Branch(deferred->entry(), hi, input, Operand(Smi::kMaxValue));
4640 __ SmiTag(result, input);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004641 __ bind(deferred->exit());
4642}
4643
4644
4645void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4646 LOperand* value,
4647 IntegerSignedness signedness) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004648 Label slow;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004649 Register src = ToRegister(value);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004650 Register dst = ToRegister(instr->result());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004651 DoubleRegister dbl_scratch = double_scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004652
4653 // Preserve the value of all registers.
4654 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4655
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004656 Label done;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004657 if (signedness == SIGNED_INT32) {
4658 // There was overflow, so bits 30 and 31 of the original integer
4659 // disagree. Try to allocate a heap number in new space and store
4660 // the value in there. If that fails, call the runtime system.
4661 if (dst.is(src)) {
4662 __ SmiUntag(src, dst);
4663 __ Xor(src, src, Operand(0x80000000));
4664 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004665 __ mtc1(src, dbl_scratch);
4666 __ cvt_d_w(dbl_scratch, dbl_scratch);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004667 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004668 __ mtc1(src, dbl_scratch);
4669 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004670 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004671
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004672 if (FLAG_inline_new) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004673 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
4674 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004675 __ Move(dst, t1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004676 __ Branch(&done);
4677 }
4678
4679 // Slow case: Call the runtime system to do the number allocation.
4680 __ bind(&slow);
4681
4682 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4683 // register is stored, as this register is in the pointer map, but contains an
4684 // integer value.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004685 __ StoreToSafepointRegisterSlot(zero_reg, dst);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004686 // NumberTagI and NumberTagD use the context from the frame, rather than
4687 // the environment's HContext or HInlinedContext value.
4688 // They only call Runtime::kAllocateHeapNumber.
4689 // The corresponding HChange instructions are added in a phase that does
4690 // not have easy access to the local context.
4691 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4692 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4693 RecordSafepointWithRegisters(
4694 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004695 __ Move(dst, v0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004696 __ Subu(dst, dst, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004697
4698 // Done. Put the value in dbl_scratch into the value of the allocated heap
4699 // number.
4700 __ bind(&done);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004701 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004702 __ Addu(dst, dst, kHeapObjectTag);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004703 __ StoreToSafepointRegisterSlot(dst, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004704}
4705
4706
4707void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004708 class DeferredNumberTagD V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004709 public:
4710 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4711 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004712 virtual void Generate() V8_OVERRIDE {
4713 codegen()->DoDeferredNumberTagD(instr_);
4714 }
4715 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004716 private:
4717 LNumberTagD* instr_;
4718 };
4719
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004720 DoubleRegister input_reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004721 Register scratch = scratch0();
4722 Register reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004723 Register temp1 = ToRegister(instr->temp());
4724 Register temp2 = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004725
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004726 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004727 if (FLAG_inline_new) {
4728 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004729 // We want the untagged address first for performance
4730 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
4731 DONT_TAG_RESULT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004732 } else {
4733 __ Branch(deferred->entry());
4734 }
4735 __ bind(deferred->exit());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004736 __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004737 // Now that we have finished with the object's real address tag it
4738 __ Addu(reg, reg, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004739}
4740
4741
4742void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4743 // TODO(3095996): Get rid of this. For now, we need to make the
4744 // result register contain a valid pointer because it is already
4745 // contained in the register pointer map.
4746 Register reg = ToRegister(instr->result());
4747 __ mov(reg, zero_reg);
4748
4749 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004750 // NumberTagI and NumberTagD use the context from the frame, rather than
4751 // the environment's HContext or HInlinedContext value.
4752 // They only call Runtime::kAllocateHeapNumber.
4753 // The corresponding HChange instructions are added in a phase that does
4754 // not have easy access to the local context.
4755 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4756 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
4757 RecordSafepointWithRegisters(
4758 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004759 __ Subu(v0, v0, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004760 __ StoreToSafepointRegisterSlot(v0, reg);
4761}
4762
4763
4764void LCodeGen::DoSmiTag(LSmiTag* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004765 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004766 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004767}
4768
4769
4770void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4771 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004772 Register input = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004773 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004774 if (instr->needs_check()) {
4775 STATIC_ASSERT(kHeapObjectTag == 1);
4776 // If the input is a HeapObject, value of scratch won't be zero.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004777 __ And(scratch, input, Operand(kHeapObjectTag));
4778 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004779 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4780 } else {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004781 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004782 }
4783}
4784
4785
4786void LCodeGen::EmitNumberUntagD(Register input_reg,
4787 DoubleRegister result_reg,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004788 bool can_convert_undefined_to_nan,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004789 bool deoptimize_on_minus_zero,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004790 LEnvironment* env,
4791 NumberUntagDMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004792 Register scratch = scratch0();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004793 Label convert, load_smi, done;
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004794 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004795 // Smi check.
4796 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004797 // Heap number map check.
4798 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4799 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004800 if (can_convert_undefined_to_nan) {
4801 __ Branch(&convert, ne, scratch, Operand(at));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004802 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004803 DeoptimizeIf(ne, env, scratch, Operand(at));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004804 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004805 // Load heap number.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004806 __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4807 if (deoptimize_on_minus_zero) {
4808 __ mfc1(at, result_reg.low());
4809 __ Branch(&done, ne, at, Operand(zero_reg));
4810 __ mfc1(scratch, result_reg.high());
4811 DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask));
4812 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004813 __ Branch(&done);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004814 if (can_convert_undefined_to_nan) {
4815 __ bind(&convert);
4816 // Convert undefined (and hole) to NaN.
4817 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4818 DeoptimizeIf(ne, env, input_reg, Operand(at));
4819 __ LoadRoot(scratch, Heap::kNanValueRootIndex);
4820 __ ldc1(result_reg, FieldMemOperand(scratch, HeapNumber::kValueOffset));
4821 __ Branch(&done);
4822 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004823 } else {
4824 __ SmiUntag(scratch, input_reg);
4825 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004826 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004827 // Smi to double register conversion
4828 __ bind(&load_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004829 // scratch: untagged value of input_reg
4830 __ mtc1(scratch, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004831 __ cvt_d_w(result_reg, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004832 __ bind(&done);
4833}
4834
4835
4836void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004837 Register input_reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004838 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004839 Register scratch2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004840 DoubleRegister double_scratch = double_scratch0();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004841 DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004842
4843 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
4844 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
4845
4846 Label done;
4847
4848 // The input is a tagged HeapObject.
4849 // Heap number map check.
4850 __ lw(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4851 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4852 // This 'at' value and scratch1 map value are used for tests in both clauses
4853 // of the if.
4854
4855 if (instr->truncating()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004856 // Performs a truncating conversion of a floating point number as used by
4857 // the JS bitwise operations.
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004858 Label no_heap_number, check_bools, check_false;
4859 __ Branch(&no_heap_number, ne, scratch1, Operand(at)); // HeapNumber map?
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004860 __ mov(scratch2, input_reg);
4861 __ TruncateHeapNumberToI(input_reg, scratch2);
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00004862 __ Branch(&done);
4863
4864 // Check for Oddballs. Undefined/False is converted to zero and True to one
4865 // for truncating conversions.
4866 __ bind(&no_heap_number);
4867 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4868 __ Branch(&check_bools, ne, input_reg, Operand(at));
4869 ASSERT(ToRegister(instr->result()).is(input_reg));
4870 __ Branch(USE_DELAY_SLOT, &done);
4871 __ mov(input_reg, zero_reg); // In delay slot.
4872
4873 __ bind(&check_bools);
4874 __ LoadRoot(at, Heap::kTrueValueRootIndex);
4875 __ Branch(&check_false, ne, scratch2, Operand(at));
4876 __ Branch(USE_DELAY_SLOT, &done);
4877 __ li(input_reg, Operand(1)); // In delay slot.
4878
4879 __ bind(&check_false);
4880 __ LoadRoot(at, Heap::kFalseValueRootIndex);
4881 DeoptimizeIf(ne, instr->environment(), scratch2, Operand(at));
4882 __ Branch(USE_DELAY_SLOT, &done);
4883 __ mov(input_reg, zero_reg); // In delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004884 } else {
4885 // Deoptimize if we don't have a heap number.
4886 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at));
4887
4888 // Load the double value.
4889 __ ldc1(double_scratch,
4890 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4891
4892 Register except_flag = scratch2;
4893 __ EmitFPUTruncate(kRoundToZero,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004894 input_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004895 double_scratch,
4896 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004897 double_scratch2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004898 except_flag,
4899 kCheckForInexactConversion);
4900
4901 // Deopt if the operation did not succeed.
4902 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4903
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004904 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4905 __ Branch(&done, ne, input_reg, Operand(zero_reg));
4906
4907 __ mfc1(scratch1, double_scratch.high());
4908 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4909 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4910 }
4911 }
4912 __ bind(&done);
4913}
4914
4915
4916void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004917 class DeferredTaggedToI V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004918 public:
4919 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4920 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00004921 virtual void Generate() V8_OVERRIDE {
4922 codegen()->DoDeferredTaggedToI(instr_);
4923 }
4924 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004925 private:
4926 LTaggedToI* instr_;
4927 };
4928
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004929 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004930 ASSERT(input->IsRegister());
4931 ASSERT(input->Equals(instr->result()));
4932
4933 Register input_reg = ToRegister(input);
4934
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004935 if (instr->hydrogen()->value()->representation().IsSmi()) {
4936 __ SmiUntag(input_reg);
4937 } else {
4938 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004939
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004940 // Let the deferred code handle the HeapObject case.
4941 __ JumpIfNotSmi(input_reg, deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004942
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004943 // Smi to int32 conversion.
4944 __ SmiUntag(input_reg);
4945 __ bind(deferred->exit());
4946 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004947}
4948
4949
4950void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004951 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004952 ASSERT(input->IsRegister());
4953 LOperand* result = instr->result();
4954 ASSERT(result->IsDoubleRegister());
4955
4956 Register input_reg = ToRegister(input);
4957 DoubleRegister result_reg = ToDoubleRegister(result);
4958
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004959 HValue* value = instr->hydrogen()->value();
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004960 NumberUntagDMode mode = value->representation().IsSmi()
4961 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004962
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004963 EmitNumberUntagD(input_reg, result_reg,
palfia@homejinni.comc4c71ea2013-08-15 08:05:35 +00004964 instr->hydrogen()->can_convert_undefined_to_nan(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004965 instr->hydrogen()->deoptimize_on_minus_zero(),
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004966 instr->environment(),
4967 mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004968}
4969
4970
4971void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
4972 Register result_reg = ToRegister(instr->result());
4973 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004974 DoubleRegister double_input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004975
4976 if (instr->truncating()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004977 __ TruncateDoubleToI(result_reg, double_input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004978 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004979 Register except_flag = LCodeGen::scratch1();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004980
4981 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004982 result_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004983 double_input,
4984 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004985 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004986 except_flag,
4987 kCheckForInexactConversion);
4988
4989 // Deopt if the operation did not succeed (except_flag != 0).
4990 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004991
4992 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4993 Label done;
4994 __ Branch(&done, ne, result_reg, Operand(zero_reg));
4995 __ mfc1(scratch1, double_input.high());
4996 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4997 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4998 __ bind(&done);
4999 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005000 }
5001}
5002
5003
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005004void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5005 Register result_reg = ToRegister(instr->result());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005006 Register scratch1 = LCodeGen::scratch0();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005007 DoubleRegister double_input = ToDoubleRegister(instr->value());
5008
5009 if (instr->truncating()) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005010 __ TruncateDoubleToI(result_reg, double_input);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005011 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00005012 Register except_flag = LCodeGen::scratch1();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005013
5014 __ EmitFPUTruncate(kRoundToMinusInf,
5015 result_reg,
5016 double_input,
5017 scratch1,
5018 double_scratch0(),
5019 except_flag,
5020 kCheckForInexactConversion);
5021
5022 // Deopt if the operation did not succeed (except_flag != 0).
5023 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
5024
5025 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5026 Label done;
5027 __ Branch(&done, ne, result_reg, Operand(zero_reg));
5028 __ mfc1(scratch1, double_input.high());
5029 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
5030 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
5031 __ bind(&done);
5032 }
5033 }
5034 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1);
5035 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg));
5036}
5037
5038
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005039void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005040 LOperand* input = instr->value();
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00005041 __ SmiTst(ToRegister(input), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005042 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
5043}
5044
5045
5046void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005047 if (!instr->hydrogen()->value()->IsHeapObject()) {
5048 LOperand* input = instr->value();
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00005049 __ SmiTst(ToRegister(input), at);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005050 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5051 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005052}
5053
5054
5055void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005056 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005057 Register scratch = scratch0();
5058
5059 __ GetObjectType(input, scratch, scratch);
5060
5061 if (instr->hydrogen()->is_interval_check()) {
5062 InstanceType first;
5063 InstanceType last;
5064 instr->hydrogen()->GetCheckInterval(&first, &last);
5065
5066 // If there is only one type in the interval check for equality.
5067 if (first == last) {
5068 DeoptimizeIf(ne, instr->environment(), scratch, Operand(first));
5069 } else {
5070 DeoptimizeIf(lo, instr->environment(), scratch, Operand(first));
5071 // Omit check for the last type.
5072 if (last != LAST_TYPE) {
5073 DeoptimizeIf(hi, instr->environment(), scratch, Operand(last));
5074 }
5075 }
5076 } else {
5077 uint8_t mask;
5078 uint8_t tag;
5079 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5080
5081 if (IsPowerOf2(mask)) {
5082 ASSERT(tag == 0 || IsPowerOf2(tag));
5083 __ And(at, scratch, mask);
5084 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment(),
5085 at, Operand(zero_reg));
5086 } else {
5087 __ And(scratch, scratch, Operand(mask));
5088 DeoptimizeIf(ne, instr->environment(), scratch, Operand(tag));
5089 }
5090 }
5091}
5092
5093
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005094void LCodeGen::DoCheckValue(LCheckValue* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005095 Register reg = ToRegister(instr->value());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005096 Handle<HeapObject> object = instr->hydrogen()->object().handle();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005097 AllowDeferredHandleDereference smi_check;
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005098 if (isolate()->heap()->InNewSpace(*object)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005099 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005100 Handle<Cell> cell = isolate()->factory()->NewCell(object);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005101 __ li(at, Operand(Handle<Object>(cell)));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00005102 __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005103 DeoptimizeIf(ne, instr->environment(), reg,
5104 Operand(at));
5105 } else {
5106 DeoptimizeIf(ne, instr->environment(), reg,
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00005107 Operand(object));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005108 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005109}
5110
5111
danno@chromium.org59400602013-08-13 17:09:37 +00005112void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
5113 {
5114 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
5115 __ push(object);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005116 __ mov(cp, zero_reg);
machenbach@chromium.orge31286d2014-01-15 10:29:52 +00005117 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005118 RecordSafepointWithRegisters(
5119 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
danno@chromium.org59400602013-08-13 17:09:37 +00005120 __ StoreToSafepointRegisterSlot(v0, scratch0());
5121 }
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00005122 __ SmiTst(scratch0(), at);
danno@chromium.org59400602013-08-13 17:09:37 +00005123 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005124}
5125
5126
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005127void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005128 class DeferredCheckMaps V8_FINAL : public LDeferredCode {
danno@chromium.org59400602013-08-13 17:09:37 +00005129 public:
5130 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
5131 : LDeferredCode(codegen), instr_(instr), object_(object) {
5132 SetExit(check_maps());
5133 }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005134 virtual void Generate() V8_OVERRIDE {
danno@chromium.org59400602013-08-13 17:09:37 +00005135 codegen()->DoDeferredInstanceMigration(instr_, object_);
5136 }
5137 Label* check_maps() { return &check_maps_; }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005138 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
danno@chromium.org59400602013-08-13 17:09:37 +00005139 private:
5140 LCheckMaps* instr_;
5141 Label check_maps_;
5142 Register object_;
5143 };
5144
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005145 if (instr->hydrogen()->CanOmitMapChecks()) return;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005146 Register map_reg = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005147 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005148 ASSERT(input->IsRegister());
5149 Register reg = ToRegister(input);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005150 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
danno@chromium.org59400602013-08-13 17:09:37 +00005151
5152 DeferredCheckMaps* deferred = NULL;
5153 if (instr->hydrogen()->has_migration_target()) {
5154 deferred = new(zone()) DeferredCheckMaps(this, instr, reg);
5155 __ bind(deferred->check_maps());
5156 }
5157
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005158 UniqueSet<Map> map_set = instr->hydrogen()->map_set();
danno@chromium.org59400602013-08-13 17:09:37 +00005159 Label success;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005160 for (int i = 0; i < map_set.size() - 1; i++) {
5161 Handle<Map> map = map_set.at(i).handle();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005162 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005163 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005164 Handle<Map> map = map_set.at(map_set.size() - 1).handle();
danno@chromium.org59400602013-08-13 17:09:37 +00005165 // Do the CompareMap() directly within the Branch() and DeoptimizeIf().
5166 if (instr->hydrogen()->has_migration_target()) {
5167 __ Branch(deferred->entry(), ne, map_reg, Operand(map));
5168 } else {
5169 DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map));
5170 }
5171
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005172 __ bind(&success);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005173}
5174
5175
5176void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5177 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
5178 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005179 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005180 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
5181}
5182
5183
5184void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5185 Register unclamped_reg = ToRegister(instr->unclamped());
5186 Register result_reg = ToRegister(instr->result());
5187 __ ClampUint8(result_reg, unclamped_reg);
5188}
5189
5190
5191void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5192 Register scratch = scratch0();
5193 Register input_reg = ToRegister(instr->unclamped());
5194 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005195 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005196 Label is_smi, done, heap_number;
5197
5198 // Both smi and heap number cases are handled.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005199 __ UntagAndJumpIfSmi(scratch, input_reg, &is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005200
5201 // Check for heap number
5202 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
5203 __ Branch(&heap_number, eq, scratch, Operand(factory()->heap_number_map()));
5204
5205 // Check for undefined. Undefined is converted to zero for clamping
5206 // conversions.
5207 DeoptimizeIf(ne, instr->environment(), input_reg,
5208 Operand(factory()->undefined_value()));
5209 __ mov(result_reg, zero_reg);
5210 __ jmp(&done);
5211
5212 // Heap number
5213 __ bind(&heap_number);
5214 __ ldc1(double_scratch0(), FieldMemOperand(input_reg,
5215 HeapNumber::kValueOffset));
5216 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
5217 __ jmp(&done);
5218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005219 __ bind(&is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005220 __ ClampUint8(result_reg, scratch);
5221
5222 __ bind(&done);
5223}
5224
5225
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005226void LCodeGen::DoAllocate(LAllocate* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005227 class DeferredAllocate V8_FINAL : public LDeferredCode {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005228 public:
5229 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5230 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005231 virtual void Generate() V8_OVERRIDE {
5232 codegen()->DoDeferredAllocate(instr_);
5233 }
5234 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005235 private:
5236 LAllocate* instr_;
5237 };
5238
5239 DeferredAllocate* deferred =
5240 new(zone()) DeferredAllocate(this, instr);
5241
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005242 Register result = ToRegister(instr->result());
5243 Register scratch = ToRegister(instr->temp1());
5244 Register scratch2 = ToRegister(instr->temp2());
5245
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005246 // Allocate memory for the object.
5247 AllocationFlags flags = TAG_OBJECT;
5248 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5249 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5250 }
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005251 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5252 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5253 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005254 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005255 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5256 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005257 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005258 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005259 if (instr->size()->IsConstantOperand()) {
5260 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005261 __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005262 } else {
5263 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005264 __ Allocate(size,
5265 result,
5266 scratch,
5267 scratch2,
5268 deferred->entry(),
5269 flags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005270 }
5271
5272 __ bind(deferred->exit());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005273
5274 if (instr->hydrogen()->MustPrefillWithFiller()) {
5275 if (instr->size()->IsConstantOperand()) {
5276 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5277 __ li(scratch, Operand(size));
5278 } else {
5279 scratch = ToRegister(instr->size());
5280 }
5281 __ Subu(scratch, scratch, Operand(kPointerSize));
5282 __ Subu(result, result, Operand(kHeapObjectTag));
5283 Label loop;
5284 __ bind(&loop);
5285 __ li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map()));
5286 __ Addu(at, result, Operand(scratch));
5287 __ sw(scratch2, MemOperand(at));
5288 __ Subu(scratch, scratch, Operand(kPointerSize));
5289 __ Branch(&loop, ge, scratch, Operand(zero_reg));
5290 __ Addu(result, result, Operand(kHeapObjectTag));
5291 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005292}
5293
5294
5295void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005296 Register result = ToRegister(instr->result());
5297
5298 // TODO(3095996): Get rid of this. For now, we need to make the
5299 // result register contain a valid pointer because it is already
5300 // contained in the register pointer map.
5301 __ mov(result, zero_reg);
5302
5303 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005304 if (instr->size()->IsRegister()) {
5305 Register size = ToRegister(instr->size());
5306 ASSERT(!size.is(result));
5307 __ SmiTag(size);
5308 __ push(size);
5309 } else {
5310 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5311 __ Push(Smi::FromInt(size));
5312 }
5313
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005314 int flags = AllocateDoubleAlignFlag::encode(
5315 instr->hydrogen()->MustAllocateDoubleAligned());
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005316 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
5317 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation());
5318 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005319 flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00005320 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
5321 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation());
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005322 flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005323 } else {
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005324 flags = AllocateTargetSpace::update(flags, NEW_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005325 }
machenbach@chromium.orgea468882013-11-18 08:53:19 +00005326 __ Push(Smi::FromInt(flags));
5327
5328 CallRuntimeFromDeferred(
5329 Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005330 __ StoreToSafepointRegisterSlot(v0, result);
5331}
5332
5333
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005334void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005335 ASSERT(ToRegister(instr->value()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005336 ASSERT(ToRegister(instr->result()).is(v0));
5337 __ push(a0);
5338 CallRuntime(Runtime::kToFastProperties, 1, instr);
5339}
5340
5341
5342void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005343 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005344 Label materialized;
5345 // Registers will be used as follows:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005346 // t3 = literals array.
5347 // a1 = regexp literal.
5348 // a0 = regexp literal clone.
5349 // a2 and t0-t2 are used as temporaries.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005350 int literal_offset =
5351 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005352 __ li(t3, instr->hydrogen()->literals());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005353 __ lw(a1, FieldMemOperand(t3, literal_offset));
5354 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5355 __ Branch(&materialized, ne, a1, Operand(at));
5356
5357 // Create regexp literal using runtime function
5358 // Result will be in v0.
5359 __ li(t2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
5360 __ li(t1, Operand(instr->hydrogen()->pattern()));
5361 __ li(t0, Operand(instr->hydrogen()->flags()));
5362 __ Push(t3, t2, t1, t0);
5363 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5364 __ mov(a1, v0);
5365
5366 __ bind(&materialized);
5367 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5368 Label allocated, runtime_allocate;
5369
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005370 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005371 __ jmp(&allocated);
5372
5373 __ bind(&runtime_allocate);
5374 __ li(a0, Operand(Smi::FromInt(size)));
5375 __ Push(a1, a0);
5376 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5377 __ pop(a1);
5378
5379 __ bind(&allocated);
5380 // Copy the content into the newly allocated memory.
5381 // (Unroll copy loop once for better throughput).
5382 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5383 __ lw(a3, FieldMemOperand(a1, i));
5384 __ lw(a2, FieldMemOperand(a1, i + kPointerSize));
5385 __ sw(a3, FieldMemOperand(v0, i));
5386 __ sw(a2, FieldMemOperand(v0, i + kPointerSize));
5387 }
5388 if ((size % (2 * kPointerSize)) != 0) {
5389 __ lw(a3, FieldMemOperand(a1, size - kPointerSize));
5390 __ sw(a3, FieldMemOperand(v0, size - kPointerSize));
5391 }
5392}
5393
5394
5395void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005396 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005397 // Use the fast case closure allocation code that allocates in new
5398 // space for nested functions that don't need literals cloning.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005399 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005400 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5401 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5402 instr->hydrogen()->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005403 __ li(a2, Operand(instr->hydrogen()->shared_info()));
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005404 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005405 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005406 __ li(a2, Operand(instr->hydrogen()->shared_info()));
5407 __ li(a1, Operand(pretenure ? factory()->true_value()
5408 : factory()->false_value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005409 __ Push(cp, a2, a1);
5410 CallRuntime(Runtime::kNewClosure, 3, instr);
5411 }
5412}
5413
5414
5415void LCodeGen::DoTypeof(LTypeof* instr) {
5416 ASSERT(ToRegister(instr->result()).is(v0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005417 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005418 __ push(input);
5419 CallRuntime(Runtime::kTypeof, 1, instr);
5420}
5421
5422
5423void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005424 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005425
5426 Register cmp1 = no_reg;
5427 Operand cmp2 = Operand(no_reg);
5428
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005429 Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_),
5430 instr->FalseLabel(chunk_),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005431 input,
5432 instr->type_literal(),
5433 cmp1,
5434 cmp2);
5435
5436 ASSERT(cmp1.is_valid());
5437 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid());
5438
5439 if (final_branch_condition != kNoCondition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005440 EmitBranch(instr, final_branch_condition, cmp1, cmp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005441 }
5442}
5443
5444
5445Condition LCodeGen::EmitTypeofIs(Label* true_label,
5446 Label* false_label,
5447 Register input,
5448 Handle<String> type_name,
5449 Register& cmp1,
5450 Operand& cmp2) {
5451 // This function utilizes the delay slot heavily. This is used to load
5452 // values that are always usable without depending on the type of the input
5453 // register.
5454 Condition final_branch_condition = kNoCondition;
5455 Register scratch = scratch0();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005456 if (type_name->Equals(heap()->number_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005457 __ JumpIfSmi(input, true_label);
5458 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5459 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
5460 cmp1 = input;
5461 cmp2 = Operand(at);
5462 final_branch_condition = eq;
5463
ulan@chromium.org750145a2013-03-07 15:14:13 +00005464 } else if (type_name->Equals(heap()->string_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005465 __ JumpIfSmi(input, false_label);
5466 __ GetObjectType(input, input, scratch);
5467 __ Branch(USE_DELAY_SLOT, false_label,
5468 ge, scratch, Operand(FIRST_NONSTRING_TYPE));
5469 // input is an object so we can load the BitFieldOffset even if we take the
5470 // other branch.
5471 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5472 __ And(at, at, 1 << Map::kIsUndetectable);
5473 cmp1 = at;
5474 cmp2 = Operand(zero_reg);
5475 final_branch_condition = eq;
5476
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005477 } else if (type_name->Equals(heap()->symbol_string())) {
5478 __ JumpIfSmi(input, false_label);
5479 __ GetObjectType(input, input, scratch);
5480 cmp1 = scratch;
5481 cmp2 = Operand(SYMBOL_TYPE);
5482 final_branch_condition = eq;
5483
ulan@chromium.org750145a2013-03-07 15:14:13 +00005484 } else if (type_name->Equals(heap()->boolean_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005485 __ LoadRoot(at, Heap::kTrueValueRootIndex);
5486 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5487 __ LoadRoot(at, Heap::kFalseValueRootIndex);
5488 cmp1 = at;
5489 cmp2 = Operand(input);
5490 final_branch_condition = eq;
5491
ulan@chromium.org750145a2013-03-07 15:14:13 +00005492 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005493 __ LoadRoot(at, Heap::kNullValueRootIndex);
5494 cmp1 = at;
5495 cmp2 = Operand(input);
5496 final_branch_condition = eq;
5497
ulan@chromium.org750145a2013-03-07 15:14:13 +00005498 } else if (type_name->Equals(heap()->undefined_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005499 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5500 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5501 // The first instruction of JumpIfSmi is an And - it is safe in the delay
5502 // slot.
5503 __ JumpIfSmi(input, false_label);
5504 // Check for undetectable objects => true.
5505 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5506 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5507 __ And(at, at, 1 << Map::kIsUndetectable);
5508 cmp1 = at;
5509 cmp2 = Operand(zero_reg);
5510 final_branch_condition = ne;
5511
ulan@chromium.org750145a2013-03-07 15:14:13 +00005512 } else if (type_name->Equals(heap()->function_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005513 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5514 __ JumpIfSmi(input, false_label);
5515 __ GetObjectType(input, scratch, input);
5516 __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE));
5517 cmp1 = input;
5518 cmp2 = Operand(JS_FUNCTION_PROXY_TYPE);
5519 final_branch_condition = eq;
5520
ulan@chromium.org750145a2013-03-07 15:14:13 +00005521 } else if (type_name->Equals(heap()->object_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005522 __ JumpIfSmi(input, false_label);
5523 if (!FLAG_harmony_typeof) {
5524 __ LoadRoot(at, Heap::kNullValueRootIndex);
5525 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5526 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005527 Register map = input;
5528 __ GetObjectType(input, map, scratch);
5529 __ Branch(false_label,
5530 lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005531 __ Branch(USE_DELAY_SLOT, false_label,
5532 gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005533 // map is still valid, so the BitField can be loaded in delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005534 // Check for undetectable objects => false.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005535 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005536 __ And(at, at, 1 << Map::kIsUndetectable);
5537 cmp1 = at;
5538 cmp2 = Operand(zero_reg);
5539 final_branch_condition = eq;
5540
5541 } else {
5542 cmp1 = at;
5543 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion.
5544 __ Branch(false_label);
5545 }
5546
5547 return final_branch_condition;
5548}
5549
5550
5551void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005552 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005553
5554 EmitIsConstructCall(temp1, scratch0());
5555
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005556 EmitBranch(instr, eq, temp1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005557 Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
5558}
5559
5560
5561void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
5562 ASSERT(!temp1.is(temp2));
5563 // Get the frame pointer for the calling frame.
5564 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5565
5566 // Skip the arguments adaptor frame if it exists.
5567 Label check_frame_marker;
5568 __ lw(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
5569 __ Branch(&check_frame_marker, ne, temp2,
5570 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
5571 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
5572
5573 // Check the marker in the calling frame.
5574 __ bind(&check_frame_marker);
5575 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
5576}
5577
5578
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005579void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005580 if (info()->IsStub()) return;
erikcorry0ad885c2011-11-21 13:51:57 +00005581 // Ensure that we have enough space after the previous lazy-bailout
5582 // instruction for patching the code here.
5583 int current_pc = masm()->pc_offset();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005584 if (current_pc < last_lazy_deopt_pc_ + space_needed) {
5585 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
erikcorry0ad885c2011-11-21 13:51:57 +00005586 ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
5587 while (padding_size > 0) {
5588 __ nop();
5589 padding_size -= Assembler::kInstrSize;
5590 }
5591 }
erikcorry0ad885c2011-11-21 13:51:57 +00005592}
5593
5594
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005595void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005596 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ulan@chromium.org6fe0fda2013-07-23 13:34:19 +00005597 last_lazy_deopt_pc_ = masm()->pc_offset();
erikcorry0ad885c2011-11-21 13:51:57 +00005598 ASSERT(instr->HasEnvironment());
5599 LEnvironment* env = instr->environment();
5600 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5601 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005602}
5603
5604
5605void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005606 Deoptimizer::BailoutType type = instr->hydrogen()->type();
5607 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
5608 // needed return address), even though the implementation of LAZY and EAGER is
5609 // now identical. When LAZY is eventually completely folded into EAGER, remove
5610 // the special case below.
5611 if (info()->IsStub() && type == Deoptimizer::EAGER) {
5612 type = Deoptimizer::LAZY;
palfia@homejinni.com04109732013-05-15 09:50:32 +00005613 }
danno@chromium.org59400602013-08-13 17:09:37 +00005614
5615 Comment(";;; deoptimize: %s", instr->hydrogen()->reason());
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +00005616 DeoptimizeIf(al, instr->environment(), type, zero_reg, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005617}
5618
5619
machenbach@chromium.org935a7792013-11-12 09:05:18 +00005620void LCodeGen::DoDummy(LDummy* instr) {
5621 // Nothing to see here, move on!
5622}
5623
5624
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005625void LCodeGen::DoDummyUse(LDummyUse* instr) {
5626 // Nothing to see here, move on!
5627}
5628
5629
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005630void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005631 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005632 LoadContextFromDeferred(instr->context());
erikcorry0ad885c2011-11-21 13:51:57 +00005633 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5634 RecordSafepointWithLazyDeopt(
5635 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5636 ASSERT(instr->HasEnvironment());
5637 LEnvironment* env = instr->environment();
5638 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005639}
5640
5641
5642void LCodeGen::DoStackCheck(LStackCheck* instr) {
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005643 class DeferredStackCheck V8_FINAL : public LDeferredCode {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005644 public:
5645 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5646 : LDeferredCode(codegen), instr_(instr) { }
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00005647 virtual void Generate() V8_OVERRIDE {
5648 codegen()->DoDeferredStackCheck(instr_);
5649 }
5650 virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005651 private:
5652 LStackCheck* instr_;
5653 };
5654
erikcorry0ad885c2011-11-21 13:51:57 +00005655 ASSERT(instr->HasEnvironment());
5656 LEnvironment* env = instr->environment();
5657 // There is no LLazyBailout instruction for stack-checks. We have to
5658 // prepare for lazy deoptimization explicitly here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005659 if (instr->hydrogen()->is_function_entry()) {
5660 // Perform stack overflow check.
5661 Label done;
5662 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5663 __ Branch(&done, hs, sp, Operand(at));
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005664 ASSERT(instr->context()->IsRegister());
5665 ASSERT(ToRegister(instr->context()).is(cp));
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005666 CallCode(isolate()->builtins()->StackCheck(),
5667 RelocInfo::CODE_TARGET,
5668 instr);
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005669 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ulan@chromium.org6fe0fda2013-07-23 13:34:19 +00005670 last_lazy_deopt_pc_ = masm()->pc_offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005671 __ bind(&done);
erikcorry0ad885c2011-11-21 13:51:57 +00005672 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5673 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005674 } else {
5675 ASSERT(instr->hydrogen()->is_backwards_branch());
5676 // Perform stack overflow check if this goto needs it before jumping.
5677 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005678 new(zone()) DeferredStackCheck(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005679 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5680 __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00005681 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
ulan@chromium.org6fe0fda2013-07-23 13:34:19 +00005682 last_lazy_deopt_pc_ = masm()->pc_offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005683 __ bind(instr->done_label());
5684 deferred_stack_check->SetExit(instr->done_label());
erikcorry0ad885c2011-11-21 13:51:57 +00005685 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5686 // Don't record a deoptimization index for the safepoint here.
5687 // This will be done explicitly when emitting call and the safepoint in
5688 // the deferred code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005689 }
5690}
5691
5692
5693void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5694 // This is a pseudo-instruction that ensures that the environment here is
5695 // properly registered for deoptimization and records the assembler's PC
5696 // offset.
5697 LEnvironment* environment = instr->environment();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005698
5699 // If the environment were already registered, we would have no way of
5700 // backpatching it with the spill slot operands.
5701 ASSERT(!environment->HasBeenRegistered());
erikcorry0ad885c2011-11-21 13:51:57 +00005702 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005703
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005704 GenerateOsrPrologue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005705}
5706
5707
ulan@chromium.org812308e2012-02-29 15:58:45 +00005708void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5709 Register result = ToRegister(instr->result());
5710 Register object = ToRegister(instr->object());
5711 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5712 DeoptimizeIf(eq, instr->environment(), object, Operand(at));
5713
5714 Register null_value = t1;
5715 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5716 DeoptimizeIf(eq, instr->environment(), object, Operand(null_value));
5717
5718 __ And(at, object, kSmiTagMask);
5719 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5720
5721 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5722 __ GetObjectType(object, a1, a1);
5723 DeoptimizeIf(le, instr->environment(), a1, Operand(LAST_JS_PROXY_TYPE));
5724
5725 Label use_cache, call_runtime;
5726 ASSERT(object.is(a0));
5727 __ CheckEnumCache(null_value, &call_runtime);
5728
5729 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
5730 __ Branch(&use_cache);
5731
5732 // Get the set of properties to enumerate.
5733 __ bind(&call_runtime);
5734 __ push(object);
5735 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5736
5737 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
5738 ASSERT(result.is(v0));
5739 __ LoadRoot(at, Heap::kMetaMapRootIndex);
5740 DeoptimizeIf(ne, instr->environment(), a1, Operand(at));
5741 __ bind(&use_cache);
5742}
5743
5744
5745void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5746 Register map = ToRegister(instr->map());
5747 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005748 Label load_cache, done;
5749 __ EnumLength(result, map);
5750 __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0)));
5751 __ li(result, Operand(isolate()->factory()->empty_fixed_array()));
5752 __ jmp(&done);
5753
5754 __ bind(&load_cache);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005755 __ LoadInstanceDescriptors(map, result);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005756 __ lw(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005757 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +00005758 __ lw(result,
5759 FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
5760 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005761
5762 __ bind(&done);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005763}
5764
5765
5766void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5767 Register object = ToRegister(instr->value());
5768 Register map = ToRegister(instr->map());
5769 __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
5770 DeoptimizeIf(ne, instr->environment(), map, Operand(scratch0()));
5771}
5772
5773
5774void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5775 Register object = ToRegister(instr->object());
5776 Register index = ToRegister(instr->index());
5777 Register result = ToRegister(instr->result());
5778 Register scratch = scratch0();
5779
5780 Label out_of_object, done;
5781 __ Branch(USE_DELAY_SLOT, &out_of_object, lt, index, Operand(zero_reg));
5782 __ sll(scratch, index, kPointerSizeLog2 - kSmiTagSize); // In delay slot.
5783
5784 STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
5785 __ Addu(scratch, object, scratch);
5786 __ lw(result, FieldMemOperand(scratch, JSObject::kHeaderSize));
5787
5788 __ Branch(&done);
5789
5790 __ bind(&out_of_object);
5791 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
5792 // Index is equal to negated out of object property index plus 1.
5793 __ Subu(scratch, result, scratch);
5794 __ lw(result, FieldMemOperand(scratch,
5795 FixedArray::kHeaderSize - kPointerSize));
5796 __ bind(&done);
5797}
5798
5799
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005800#undef __
5801
5802} } // namespace v8::internal