blob: 05fa79247e5fa6722fbe49f294c7a4ec10ca40ca [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
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"
34
35namespace v8 {
36namespace internal {
37
38
39class SafepointGenerator : public CallWrapper {
40 public:
41 SafepointGenerator(LCodeGen* codegen,
42 LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +000043 Safepoint::DeoptMode mode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000044 : codegen_(codegen),
45 pointers_(pointers),
erikcorry0ad885c2011-11-21 13:51:57 +000046 deopt_mode_(mode) { }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000047 virtual ~SafepointGenerator() { }
48
erikcorry0ad885c2011-11-21 13:51:57 +000049 virtual void BeforeCall(int call_size) const { }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000050
51 virtual void AfterCall() const {
erikcorry0ad885c2011-11-21 13:51:57 +000052 codegen_->RecordSafepoint(pointers_, deopt_mode_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000053 }
54
55 private:
56 LCodeGen* codegen_;
57 LPointerMap* pointers_;
erikcorry0ad885c2011-11-21 13:51:57 +000058 Safepoint::DeoptMode deopt_mode_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000059};
60
61
62#define __ masm()->
63
64bool LCodeGen::GenerateCode() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000065 HPhase phase("Z_Code generation", chunk());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000066 ASSERT(is_unused());
67 status_ = GENERATING;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000068
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000069 // Open a frame scope to indicate that there is a frame on the stack. The
70 // NONE indicates that the scope shouldn't actually generate code to set up
71 // the frame (that is done in GeneratePrologue).
72 FrameScope frame_scope(masm_, StackFrame::NONE);
73
74 return GeneratePrologue() &&
75 GenerateBody() &&
76 GenerateDeferredCode() &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000077 GenerateDeoptJumpTable() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000078 GenerateSafepointTable();
79}
80
81
82void LCodeGen::FinishCode(Handle<Code> code) {
83 ASSERT(is_done());
84 code->set_stack_slots(GetStackSlotCount());
85 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +000086 if (FLAG_weak_embedded_maps_in_optimized_code) {
87 RegisterDependentCodeForEmbeddedMaps(code);
88 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000089 PopulateDeoptimizationData(code);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000090 for (int i = 0 ; i < prototype_maps_.length(); i++) {
91 prototype_maps_.at(i)->AddDependentCode(
92 DependentCode::kPrototypeCheckGroup, code);
93 }
danno@chromium.orgf005df62013-04-30 16:36:45 +000094 for (int i = 0 ; i < transition_maps_.length(); i++) {
95 transition_maps_.at(i)->AddDependentCode(
96 DependentCode::kTransitionGroup, code);
97 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000098 if (graph()->depends_on_empty_array_proto_elements()) {
99 isolate()->initial_object_prototype()->map()->AddDependentCode(
100 DependentCode::kElementsCantBeAddedGroup, code);
101 isolate()->initial_array_prototype()->map()->AddDependentCode(
102 DependentCode::kElementsCantBeAddedGroup, code);
103 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000104}
105
106
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000107void LChunkBuilder::Abort(const char* reason) {
108 info()->set_bailout_reason(reason);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109 status_ = ABORTED;
110}
111
112
113void LCodeGen::Comment(const char* format, ...) {
114 if (!FLAG_code_comments) return;
115 char buffer[4 * KB];
116 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
117 va_list arguments;
118 va_start(arguments, format);
119 builder.AddFormattedList(format, arguments);
120 va_end(arguments);
121
122 // Copy the string before recording it in the assembler to avoid
123 // issues when the stack allocated buffer goes out of scope.
124 size_t length = builder.position();
125 Vector<char> copy = Vector<char>::New(length + 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000126 OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000127 masm()->RecordComment(copy.start());
128}
129
130
131bool 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
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000149 // Strict mode functions and builtins need to replace the receiver
150 // with undefined when called as functions (without an explicit
151 // receiver object). r5 is zero for method calls and non-zero for
152 // function calls.
153 if (!info_->is_classic_mode() || info_->is_native()) {
154 Label ok;
155 __ Branch(&ok, eq, t1, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000156
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000157 int receiver_offset = scope()->num_parameters() * kPointerSize;
158 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
159 __ sw(a2, MemOperand(sp, receiver_offset));
160 __ bind(&ok);
161 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000162 }
163
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000164 info()->set_prologue_offset(masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000165 if (NeedsEagerFrame()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000166 if (info()->IsStub()) {
167 __ Push(ra, fp, cp);
168 __ Push(Smi::FromInt(StackFrame::STUB));
169 // Adjust FP to point to saved FP.
170 __ Addu(fp, sp, Operand(2 * kPointerSize));
171 } else {
172 // The following three instructions must remain together and unmodified
173 // for code aging to work properly.
174 __ Push(ra, fp, cp, a1);
175 // Add unused load of ip to ensure prologue sequence is identical for
176 // full-codegen and lithium-codegen.
177 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
178 // Adj. FP to point to saved FP.
179 __ Addu(fp, sp, Operand(2 * kPointerSize));
180 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000181 frame_is_built_ = true;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000182 info_->AddNoFrameRange(0, masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000183 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000184
185 // Reserve space for the stack slots needed by the code.
186 int slots = GetStackSlotCount();
187 if (slots > 0) {
188 if (FLAG_debug_code) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000189 __ Subu(sp, sp, Operand(slots * kPointerSize));
190 __ push(a0);
191 __ push(a1);
192 __ Addu(a0, sp, Operand(slots * kPointerSize));
193 __ li(a1, Operand(kSlotsZapValue));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000194 Label loop;
195 __ bind(&loop);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000196 __ Subu(a0, a0, Operand(kPointerSize));
197 __ sw(a1, MemOperand(a0, 2 * kPointerSize));
198 __ Branch(&loop, ne, a0, Operand(sp));
199 __ pop(a1);
200 __ pop(a0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000201 } else {
202 __ Subu(sp, sp, Operand(slots * kPointerSize));
203 }
204 }
205
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000206 if (info()->saves_caller_doubles()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000207 Comment(";;; Save clobbered callee double registers");
208 int count = 0;
209 BitVector* doubles = chunk()->allocated_double_registers();
210 BitVector::Iterator save_iterator(doubles);
211 while (!save_iterator.Done()) {
212 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
213 MemOperand(sp, count * kDoubleSize));
214 save_iterator.Advance();
215 count++;
216 }
217 }
218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000219 // Possibly allocate a local context.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000220 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000221 if (heap_slots > 0) {
222 Comment(";;; Allocate local context");
223 // Argument to NewContext is the function, which is in a1.
224 __ push(a1);
225 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
226 FastNewContextStub stub(heap_slots);
227 __ CallStub(&stub);
228 } else {
229 __ CallRuntime(Runtime::kNewFunctionContext, 1);
230 }
erikcorry0ad885c2011-11-21 13:51:57 +0000231 RecordSafepoint(Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000232 // Context is returned in both v0 and cp. It replaces the context
233 // passed to us. It's saved in the stack and kept live in cp.
234 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
235 // Copy any necessary parameters into the context.
236 int num_parameters = scope()->num_parameters();
237 for (int i = 0; i < num_parameters; i++) {
238 Variable* var = scope()->parameter(i);
239 if (var->IsContextSlot()) {
240 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
241 (num_parameters - 1 - i) * kPointerSize;
242 // Load parameter from stack.
243 __ lw(a0, MemOperand(fp, parameter_offset));
244 // Store it in the context.
245 MemOperand target = ContextOperand(cp, var->index());
246 __ sw(a0, target);
247 // Update the write barrier. This clobbers a3 and a0.
248 __ RecordWriteContextSlot(
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000249 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000250 }
251 }
252 Comment(";;; End allocate local context");
253 }
254
255 // Trace the call.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000256 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000257 __ CallRuntime(Runtime::kTraceEnter, 0);
258 }
erikcorry0ad885c2011-11-21 13:51:57 +0000259 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000260 return !is_aborted();
261}
262
263
264bool LCodeGen::GenerateBody() {
265 ASSERT(is_generating());
266 bool emit_instructions = true;
267 for (current_instruction_ = 0;
268 !is_aborted() && current_instruction_ < instructions_->length();
269 current_instruction_++) {
270 LInstruction* instr = instructions_->at(current_instruction_);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000271
272 // Don't emit code for basic blocks with a replacement.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000273 if (instr->IsLabel()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000274 emit_instructions = !LLabel::cast(instr)->HasReplacement();
275 }
276 if (!emit_instructions) continue;
277
278 if (FLAG_code_comments && instr->HasInterestingComment(this)) {
279 Comment(";;; <@%d,#%d> %s",
280 current_instruction_,
281 instr->hydrogen_value()->id(),
282 instr->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000283 }
284
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000285 instr->CompileToNative(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000286 }
287 return !is_aborted();
288}
289
290
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000291bool LCodeGen::GenerateDeferredCode() {
292 ASSERT(is_generating());
293 if (deferred_.length() > 0) {
294 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
295 LDeferredCode* code = deferred_[i];
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000296 Comment(";;; <@%d,#%d> "
297 "-------------------- Deferred %s --------------------",
298 code->instruction_index(),
299 code->instr()->hydrogen_value()->id(),
300 code->instr()->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000301 __ bind(code->entry());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000302 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000303 Comment(";;; Build frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000304 ASSERT(!frame_is_built_);
305 ASSERT(info()->IsStub());
306 frame_is_built_ = true;
307 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
308 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
309 __ push(scratch0());
310 __ Addu(fp, sp, Operand(2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000311 Comment(";;; Deferred code");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000312 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000313 code->Generate();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000314 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000315 Comment(";;; Destroy frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000316 ASSERT(frame_is_built_);
317 __ pop(at);
318 __ MultiPop(cp.bit() | fp.bit() | ra.bit());
319 frame_is_built_ = false;
320 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000321 __ jmp(code->exit());
322 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000323 }
324 // Deferred code is the last part of the instruction sequence. Mark
325 // the generated code as done unless we bailed out.
326 if (!is_aborted()) status_ = DONE;
327 return !is_aborted();
328}
329
330
331bool LCodeGen::GenerateDeoptJumpTable() {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000332 // Check that the jump table is accessible from everywhere in the function
333 // code, i.e. that offsets to the table can be encoded in the 16bit signed
334 // immediate of a branch instruction.
335 // To simplify we consider the code size from the first instruction to the
336 // end of the jump table.
337 if (!is_int16((masm()->pc_offset() / Assembler::kInstrSize) +
338 deopt_jump_table_.length() * 12)) {
339 Abort("Generated code is too large");
340 }
341
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000342 if (deopt_jump_table_.length() > 0) {
343 Comment(";;; -------------------- Jump table --------------------");
344 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000345 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000346 Label table_start;
347 __ bind(&table_start);
348 Label needs_frame_not_call;
349 Label needs_frame_is_call;
350 for (int i = 0; i < deopt_jump_table_.length(); i++) {
351 __ bind(&deopt_jump_table_[i].label);
352 Address entry = deopt_jump_table_[i].address;
palfia@homejinni.com04109732013-05-15 09:50:32 +0000353 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000354 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000355 if (id == Deoptimizer::kNotDeoptimizationEntry) {
356 Comment(";;; jump table entry %d.", i);
357 } else {
358 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
359 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000360 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
361 if (deopt_jump_table_[i].needs_frame) {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000362 if (type == Deoptimizer::LAZY) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000363 if (needs_frame_is_call.is_bound()) {
364 __ Branch(&needs_frame_is_call);
365 } else {
366 __ bind(&needs_frame_is_call);
367 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
368 // This variant of deopt can only be used with stubs. Since we don't
369 // have a function pointer to install in the stack frame that we're
370 // building, install a special marker there instead.
371 ASSERT(info()->IsStub());
372 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
373 __ push(scratch0());
374 __ Addu(fp, sp, Operand(2 * kPointerSize));
375 __ Call(t9);
376 }
377 } else {
378 if (needs_frame_not_call.is_bound()) {
379 __ Branch(&needs_frame_not_call);
380 } else {
381 __ bind(&needs_frame_not_call);
382 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
383 // This variant of deopt can only be used with stubs. Since we don't
384 // have a function pointer to install in the stack frame that we're
385 // building, install a special marker there instead.
386 ASSERT(info()->IsStub());
387 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
388 __ push(scratch0());
389 __ Addu(fp, sp, Operand(2 * kPointerSize));
390 __ Jump(t9);
391 }
392 }
393 } else {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000394 if (type == Deoptimizer::LAZY) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000395 __ Call(t9);
396 } else {
397 __ Jump(t9);
398 }
399 }
400 }
401 __ RecordComment("]");
402
403 // The deoptimization jump table is the last part of the instruction
404 // sequence. Mark the generated code as done unless we bailed out.
405 if (!is_aborted()) status_ = DONE;
406 return !is_aborted();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000407}
408
409
410bool LCodeGen::GenerateSafepointTable() {
411 ASSERT(is_done());
412 safepoints_.Emit(masm(), GetStackSlotCount());
413 return !is_aborted();
414}
415
416
417Register LCodeGen::ToRegister(int index) const {
418 return Register::FromAllocationIndex(index);
419}
420
421
422DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
423 return DoubleRegister::FromAllocationIndex(index);
424}
425
426
427Register LCodeGen::ToRegister(LOperand* op) const {
428 ASSERT(op->IsRegister());
429 return ToRegister(op->index());
430}
431
432
433Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
434 if (op->IsRegister()) {
435 return ToRegister(op->index());
436 } else if (op->IsConstantOperand()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000437 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000438 HConstant* constant = chunk_->LookupConstant(const_op);
439 Handle<Object> literal = constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000440 Representation r = chunk_->LookupLiteralRepresentation(const_op);
441 if (r.IsInteger32()) {
442 ASSERT(literal->IsNumber());
443 __ li(scratch, Operand(static_cast<int32_t>(literal->Number())));
444 } else if (r.IsDouble()) {
445 Abort("EmitLoadRegister: Unsupported double immediate.");
446 } else {
447 ASSERT(r.IsTagged());
448 if (literal->IsSmi()) {
449 __ li(scratch, Operand(literal));
450 } else {
451 __ LoadHeapObject(scratch, Handle<HeapObject>::cast(literal));
452 }
453 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000454 return scratch;
455 } else if (op->IsStackSlot() || op->IsArgument()) {
456 __ lw(scratch, ToMemOperand(op));
457 return scratch;
458 }
459 UNREACHABLE();
460 return scratch;
461}
462
463
464DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
465 ASSERT(op->IsDoubleRegister());
466 return ToDoubleRegister(op->index());
467}
468
469
470DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
471 FloatRegister flt_scratch,
472 DoubleRegister dbl_scratch) {
473 if (op->IsDoubleRegister()) {
474 return ToDoubleRegister(op->index());
475 } else if (op->IsConstantOperand()) {
476 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000477 HConstant* constant = chunk_->LookupConstant(const_op);
478 Handle<Object> literal = constant->handle();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000479 Representation r = chunk_->LookupLiteralRepresentation(const_op);
480 if (r.IsInteger32()) {
481 ASSERT(literal->IsNumber());
482 __ li(at, Operand(static_cast<int32_t>(literal->Number())));
483 __ mtc1(at, flt_scratch);
484 __ cvt_d_w(dbl_scratch, flt_scratch);
485 return dbl_scratch;
486 } else if (r.IsDouble()) {
487 Abort("unsupported double immediate");
488 } else if (r.IsTagged()) {
489 Abort("unsupported tagged immediate");
490 }
491 } else if (op->IsStackSlot() || op->IsArgument()) {
492 MemOperand mem_op = ToMemOperand(op);
493 __ ldc1(dbl_scratch, mem_op);
494 return dbl_scratch;
495 }
496 UNREACHABLE();
497 return dbl_scratch;
498}
499
500
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000501Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000502 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000503 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000504 return constant->handle();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000505}
506
507
508bool LCodeGen::IsInteger32(LConstantOperand* op) const {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000509 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000510}
511
512
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000513bool LCodeGen::IsSmi(LConstantOperand* op) const {
514 return chunk_->LookupLiteralRepresentation(op).IsSmi();
515}
516
517
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000518int LCodeGen::ToInteger32(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000519 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000520 return constant->Integer32Value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000521}
522
523
524double LCodeGen::ToDouble(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000525 HConstant* constant = chunk_->LookupConstant(op);
526 ASSERT(constant->HasDoubleValue());
527 return constant->DoubleValue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000528}
529
530
531Operand LCodeGen::ToOperand(LOperand* op) {
532 if (op->IsConstantOperand()) {
533 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000534 HConstant* constant = chunk()->LookupConstant(const_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000535 Representation r = chunk_->LookupLiteralRepresentation(const_op);
536 if (r.IsInteger32()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000537 ASSERT(constant->HasInteger32Value());
538 return Operand(constant->Integer32Value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000539 } else if (r.IsDouble()) {
540 Abort("ToOperand Unsupported double immediate.");
541 }
542 ASSERT(r.IsTagged());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000543 return Operand(constant->handle());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000544 } else if (op->IsRegister()) {
545 return Operand(ToRegister(op));
546 } else if (op->IsDoubleRegister()) {
547 Abort("ToOperand IsDoubleRegister unimplemented");
548 return Operand(0);
549 }
550 // Stack slots not implemented, use ToMemOperand instead.
551 UNREACHABLE();
552 return Operand(0);
553}
554
555
556MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
557 ASSERT(!op->IsRegister());
558 ASSERT(!op->IsDoubleRegister());
559 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000560 return MemOperand(fp, StackSlotOffset(op->index()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000561}
562
563
564MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
565 ASSERT(op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000566 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000567}
568
569
570void LCodeGen::WriteTranslation(LEnvironment* environment,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000571 Translation* translation,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000572 int* pushed_arguments_index,
573 int* pushed_arguments_count) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000574 if (environment == NULL) return;
575
576 // The translation includes one command per value in the environment.
577 int translation_size = environment->values()->length();
578 // The output frame height does not include the parameters.
579 int height = translation_size - environment->parameter_count();
580
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000581 // Function parameters are arguments to the outermost environment. The
582 // arguments index points to the first element of a sequence of tagged
583 // values on the stack that represent the arguments. This needs to be
584 // kept in sync with the LArgumentsElements implementation.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000585 *pushed_arguments_index = -environment->parameter_count();
586 *pushed_arguments_count = environment->parameter_count();
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000587
588 WriteTranslation(environment->outer(),
589 translation,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000590 pushed_arguments_index,
591 pushed_arguments_count);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000592 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000593 !info()->closure().is_identical_to(environment->closure());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000594 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000595 ? DefineDeoptimizationLiteral(environment->closure())
596 : Translation::kSelfLiteralId;
597
ulan@chromium.org812308e2012-02-29 15:58:45 +0000598 switch (environment->frame_type()) {
599 case JS_FUNCTION:
600 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
601 break;
602 case JS_CONSTRUCT:
603 translation->BeginConstructStubFrame(closure_id, translation_size);
604 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000605 case JS_GETTER:
606 ASSERT(translation_size == 1);
607 ASSERT(height == 0);
608 translation->BeginGetterStubFrame(closure_id);
609 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000610 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000611 ASSERT(translation_size == 2);
612 ASSERT(height == 0);
613 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000614 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000615 case STUB:
616 translation->BeginCompiledStubFrame();
617 break;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000618 case ARGUMENTS_ADAPTOR:
619 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
620 break;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000621 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000622
623 // Inlined frames which push their arguments cause the index to be
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000624 // bumped and another stack area to be used for materialization,
625 // otherwise actual argument values are unknown for inlined frames.
626 bool arguments_known = true;
627 int arguments_index = *pushed_arguments_index;
628 int arguments_count = *pushed_arguments_count;
629 if (environment->entry() != NULL) {
630 arguments_known = environment->entry()->arguments_pushed();
631 arguments_index = arguments_index < 0
632 ? GetStackSlotCount() : arguments_index + arguments_count;
633 arguments_count = environment->entry()->arguments_count() + 1;
634 if (environment->entry()->arguments_pushed()) {
635 *pushed_arguments_index = arguments_index;
636 *pushed_arguments_count = arguments_count;
637 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000638 }
639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000640 for (int i = 0; i < translation_size; ++i) {
641 LOperand* value = environment->values()->at(i);
642 // spilled_registers_ and spilled_double_registers_ are either
643 // both NULL or both set.
644 if (environment->spilled_registers() != NULL && value != NULL) {
645 if (value->IsRegister() &&
646 environment->spilled_registers()[value->index()] != NULL) {
647 translation->MarkDuplicate();
648 AddToTranslation(translation,
649 environment->spilled_registers()[value->index()],
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000650 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000651 environment->HasUint32ValueAt(i),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000652 arguments_known,
653 arguments_index,
654 arguments_count);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000655 } else if (
656 value->IsDoubleRegister() &&
657 environment->spilled_double_registers()[value->index()] != NULL) {
658 translation->MarkDuplicate();
659 AddToTranslation(
660 translation,
661 environment->spilled_double_registers()[value->index()],
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000662 false,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000663 false,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000664 arguments_known,
665 arguments_index,
666 arguments_count);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000667 }
668 }
669
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000670 AddToTranslation(translation,
671 value,
672 environment->HasTaggedValueAt(i),
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000673 environment->HasUint32ValueAt(i),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000674 arguments_known,
675 arguments_index,
676 arguments_count);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000677 }
678}
679
680
681void LCodeGen::AddToTranslation(Translation* translation,
682 LOperand* op,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000683 bool is_tagged,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000684 bool is_uint32,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000685 bool arguments_known,
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000686 int arguments_index,
687 int arguments_count) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688 if (op == NULL) {
689 // TODO(twuerthinger): Introduce marker operands to indicate that this value
690 // is not present and must be reconstructed from the deoptimizer. Currently
691 // this is only used for the arguments object.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000692 translation->StoreArgumentsObject(
693 arguments_known, arguments_index, arguments_count);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000694 } else if (op->IsStackSlot()) {
695 if (is_tagged) {
696 translation->StoreStackSlot(op->index());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000697 } else if (is_uint32) {
698 translation->StoreUint32StackSlot(op->index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000699 } else {
700 translation->StoreInt32StackSlot(op->index());
701 }
702 } else if (op->IsDoubleStackSlot()) {
703 translation->StoreDoubleStackSlot(op->index());
704 } else if (op->IsArgument()) {
705 ASSERT(is_tagged);
706 int src_index = GetStackSlotCount() + op->index();
707 translation->StoreStackSlot(src_index);
708 } else if (op->IsRegister()) {
709 Register reg = ToRegister(op);
710 if (is_tagged) {
711 translation->StoreRegister(reg);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000712 } else if (is_uint32) {
713 translation->StoreUint32Register(reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000714 } else {
715 translation->StoreInt32Register(reg);
716 }
717 } else if (op->IsDoubleRegister()) {
718 DoubleRegister reg = ToDoubleRegister(op);
719 translation->StoreDoubleRegister(reg);
720 } else if (op->IsConstantOperand()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000721 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
722 int src_index = DefineDeoptimizationLiteral(constant->handle());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000723 translation->StoreLiteral(src_index);
724 } else {
725 UNREACHABLE();
726 }
727}
728
729
730void LCodeGen::CallCode(Handle<Code> code,
731 RelocInfo::Mode mode,
732 LInstruction* instr) {
733 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
734}
735
736
737void LCodeGen::CallCodeGeneric(Handle<Code> code,
738 RelocInfo::Mode mode,
739 LInstruction* instr,
740 SafepointMode safepoint_mode) {
741 ASSERT(instr != NULL);
742 LPointerMap* pointers = instr->pointer_map();
743 RecordPosition(pointers->position());
744 __ Call(code, mode);
erikcorry0ad885c2011-11-21 13:51:57 +0000745 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000746}
747
748
749void LCodeGen::CallRuntime(const Runtime::Function* function,
750 int num_arguments,
751 LInstruction* instr) {
752 ASSERT(instr != NULL);
753 LPointerMap* pointers = instr->pointer_map();
754 ASSERT(pointers != NULL);
755 RecordPosition(pointers->position());
756
757 __ CallRuntime(function, num_arguments);
erikcorry0ad885c2011-11-21 13:51:57 +0000758 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000759}
760
761
762void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
763 int argc,
764 LInstruction* instr) {
765 __ CallRuntimeSaveDoubles(id);
766 RecordSafepointWithRegisters(
erikcorry0ad885c2011-11-21 13:51:57 +0000767 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000768}
769
770
erikcorry0ad885c2011-11-21 13:51:57 +0000771void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
772 Safepoint::DeoptMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000773 if (!environment->HasBeenRegistered()) {
774 // Physical stack frame layout:
775 // -x ............. -4 0 ..................................... y
776 // [incoming arguments] [spill slots] [pushed outgoing arguments]
777
778 // Layout of the environment:
779 // 0 ..................................................... size-1
780 // [parameters] [locals] [expression stack including arguments]
781
782 // Layout of the translation:
783 // 0 ........................................................ size - 1 + 4
784 // [expression stack including arguments] [locals] [4 words] [parameters]
785 // |>------------ translation_size ------------<|
786
787 int frame_count = 0;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000788 int jsframe_count = 0;
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000789 int args_index = 0;
790 int args_count = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000791 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
792 ++frame_count;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000793 if (e->frame_type() == JS_FUNCTION) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000794 ++jsframe_count;
795 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000796 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000797 Translation translation(&translations_, frame_count, jsframe_count, zone());
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000798 WriteTranslation(environment, &translation, &args_index, &args_count);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000799 int deoptimization_index = deoptimizations_.length();
erikcorry0ad885c2011-11-21 13:51:57 +0000800 int pc_offset = masm()->pc_offset();
801 environment->Register(deoptimization_index,
802 translation.index(),
803 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000804 deoptimizations_.Add(environment, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000805 }
806}
807
808
809void LCodeGen::DeoptimizeIf(Condition cc,
810 LEnvironment* environment,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000811 Deoptimizer::BailoutType bailout_type,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 Register src1,
813 const Operand& src2) {
erikcorry0ad885c2011-11-21 13:51:57 +0000814 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000815 ASSERT(environment->HasBeenRegistered());
816 int id = environment->deoptimization_index();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000817 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000818 Address entry =
819 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000820 if (entry == NULL) {
821 Abort("bailout was not prepared");
822 return;
823 }
824
825 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000826 if (FLAG_deopt_every_n_times == 1 &&
827 !info()->IsStub() &&
828 info()->opt_count() == id) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000829 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
830 return;
831 }
832
833 if (FLAG_trap_on_deopt) {
834 Label skip;
835 if (cc != al) {
836 __ Branch(&skip, NegateCondition(cc), src1, src2);
837 }
838 __ stop("trap_on_deopt");
839 __ bind(&skip);
840 }
841
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000842 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000843 bool needs_lazy_deopt = info()->IsStub();
844 if (cc == al && frame_is_built_) {
845 if (needs_lazy_deopt) {
846 __ Call(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2);
847 } else {
848 __ Jump(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2);
849 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000850 } else {
851 // We often have several deopts to the same entry, reuse the last
852 // jump entry if this is the case.
853 if (deopt_jump_table_.is_empty() ||
854 (deopt_jump_table_.last().address != entry) ||
palfia@homejinni.com04109732013-05-15 09:50:32 +0000855 (deopt_jump_table_.last().bailout_type != bailout_type) ||
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000856 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000857 Deoptimizer::JumpTableEntry table_entry(entry,
858 bailout_type,
859 !frame_is_built_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000860 deopt_jump_table_.Add(table_entry, zone());
861 }
862 __ Branch(&deopt_jump_table_.last().label, cc, src1, src2);
863 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000864}
865
866
palfia@homejinni.com04109732013-05-15 09:50:32 +0000867void LCodeGen::DeoptimizeIf(Condition cc,
868 LEnvironment* environment,
869 Register src1,
870 const Operand& src2) {
871 Deoptimizer::BailoutType bailout_type = info()->IsStub()
872 ? Deoptimizer::LAZY
873 : Deoptimizer::EAGER;
874 DeoptimizeIf(cc, environment, bailout_type, src1, src2);
875}
876
877
878void LCodeGen::SoftDeoptimize(LEnvironment* environment,
879 Register src1,
880 const Operand& src2) {
881 ASSERT(!info()->IsStub());
882 DeoptimizeIf(al, environment, Deoptimizer::SOFT, src1, src2);
883}
884
885
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000886void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
887 ZoneList<Handle<Map> > maps(1, zone());
888 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
889 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
890 RelocInfo::Mode mode = it.rinfo()->rmode();
891 if (mode == RelocInfo::EMBEDDED_OBJECT &&
892 it.rinfo()->target_object()->IsMap()) {
893 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
894 if (map->CanTransition()) {
895 maps.Add(map, zone());
896 }
897 }
898 }
899#ifdef VERIFY_HEAP
900 // This disables verification of weak embedded maps after full GC.
901 // AddDependentCode can cause a GC, which would observe the state where
902 // this code is not yet in the depended code lists of the embedded maps.
903 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps;
904#endif
905 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000906 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000907 }
908}
909
910
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000911void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
912 int length = deoptimizations_.length();
913 if (length == 0) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000914 Handle<DeoptimizationInputData> data =
915 factory()->NewDeoptimizationInputData(length, TENURED);
916
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000917 Handle<ByteArray> translations =
918 translations_.CreateByteArray(isolate()->factory());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000919 data->SetTranslationByteArray(*translations);
920 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
921
922 Handle<FixedArray> literals =
923 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000924 { ALLOW_HANDLE_DEREF(isolate(),
925 "copying a ZoneList of handles into a FixedArray");
926 for (int i = 0; i < deoptimization_literals_.length(); i++) {
927 literals->set(i, *deoptimization_literals_[i]);
928 }
929 data->SetLiteralArray(*literals);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000930 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000931
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000932 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000933 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
934
935 // Populate the deoptimization entries.
936 for (int i = 0; i < length; i++) {
937 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000938 data->SetAstId(i, env->ast_id());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000939 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
940 data->SetArgumentsStackHeight(i,
941 Smi::FromInt(env->arguments_stack_height()));
erikcorry0ad885c2011-11-21 13:51:57 +0000942 data->SetPc(i, Smi::FromInt(env->pc_offset()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000943 }
944 code->set_deoptimization_data(*data);
945}
946
947
948int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
949 int result = deoptimization_literals_.length();
950 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
951 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
952 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000953 deoptimization_literals_.Add(literal, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000954 return result;
955}
956
957
958void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
959 ASSERT(deoptimization_literals_.length() == 0);
960
961 const ZoneList<Handle<JSFunction> >* inlined_closures =
962 chunk()->inlined_closures();
963
964 for (int i = 0, length = inlined_closures->length();
965 i < length;
966 i++) {
967 DefineDeoptimizationLiteral(inlined_closures->at(i));
968 }
969
970 inlined_function_count_ = deoptimization_literals_.length();
971}
972
973
erikcorry0ad885c2011-11-21 13:51:57 +0000974void LCodeGen::RecordSafepointWithLazyDeopt(
975 LInstruction* instr, SafepointMode safepoint_mode) {
976 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
977 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
978 } else {
979 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
980 RecordSafepointWithRegisters(
981 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
982 }
983}
984
985
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000986void LCodeGen::RecordSafepoint(
987 LPointerMap* pointers,
988 Safepoint::Kind kind,
989 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000990 Safepoint::DeoptMode deopt_mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000991 ASSERT(expected_safepoint_kind_ == kind);
992
993 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
994 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
erikcorry0ad885c2011-11-21 13:51:57 +0000995 kind, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000996 for (int i = 0; i < operands->length(); i++) {
997 LOperand* pointer = operands->at(i);
998 if (pointer->IsStackSlot()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000999 safepoint.DefinePointerSlot(pointer->index(), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001000 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001001 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001002 }
1003 }
1004 if (kind & Safepoint::kWithRegisters) {
1005 // Register cp always contains a pointer to the context.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001006 safepoint.DefinePointerRegister(cp, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001007 }
1008}
1009
1010
1011void LCodeGen::RecordSafepoint(LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +00001012 Safepoint::DeoptMode deopt_mode) {
1013 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001014}
1015
1016
erikcorry0ad885c2011-11-21 13:51:57 +00001017void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001018 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
erikcorry0ad885c2011-11-21 13:51:57 +00001019 RecordSafepoint(&empty_pointers, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001020}
1021
1022
1023void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
1024 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +00001025 Safepoint::DeoptMode deopt_mode) {
1026 RecordSafepoint(
1027 pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001028}
1029
1030
1031void LCodeGen::RecordSafepointWithRegistersAndDoubles(
1032 LPointerMap* pointers,
1033 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +00001034 Safepoint::DeoptMode deopt_mode) {
1035 RecordSafepoint(
1036 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001037}
1038
1039
1040void LCodeGen::RecordPosition(int position) {
1041 if (position == RelocInfo::kNoPosition) return;
1042 masm()->positions_recorder()->RecordPosition(position);
1043}
1044
1045
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001046static const char* LabelType(LLabel* label) {
1047 if (label->is_loop_header()) return " (loop header)";
1048 if (label->is_osr_entry()) return " (OSR entry)";
1049 return "";
1050}
1051
1052
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001053void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001054 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
1055 current_instruction_,
1056 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +00001057 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001058 LabelType(label));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001059 __ bind(label->label());
1060 current_block_ = label->block_id();
1061 DoGap(label);
1062}
1063
1064
1065void LCodeGen::DoParallelMove(LParallelMove* move) {
1066 resolver_.Resolve(move);
1067}
1068
1069
1070void LCodeGen::DoGap(LGap* gap) {
1071 for (int i = LGap::FIRST_INNER_POSITION;
1072 i <= LGap::LAST_INNER_POSITION;
1073 i++) {
1074 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
1075 LParallelMove* move = gap->GetParallelMove(inner_pos);
1076 if (move != NULL) DoParallelMove(move);
1077 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001078}
1079
1080
1081void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
1082 DoGap(instr);
1083}
1084
1085
1086void LCodeGen::DoParameter(LParameter* instr) {
1087 // Nothing to do.
1088}
1089
1090
1091void LCodeGen::DoCallStub(LCallStub* instr) {
1092 ASSERT(ToRegister(instr->result()).is(v0));
1093 switch (instr->hydrogen()->major_key()) {
1094 case CodeStub::RegExpConstructResult: {
1095 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001096 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001097 break;
1098 }
1099 case CodeStub::RegExpExec: {
1100 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001101 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001102 break;
1103 }
1104 case CodeStub::SubString: {
1105 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001106 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001107 break;
1108 }
1109 case CodeStub::NumberToString: {
1110 NumberToStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001111 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001112 break;
1113 }
1114 case CodeStub::StringAdd: {
1115 StringAddStub stub(NO_STRING_ADD_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001116 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001117 break;
1118 }
1119 case CodeStub::StringCompare: {
1120 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001121 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001122 break;
1123 }
1124 case CodeStub::TranscendentalCache: {
1125 __ lw(a0, MemOperand(sp, 0));
1126 TranscendentalCacheStub stub(instr->transcendental_type(),
1127 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001128 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001129 break;
1130 }
1131 default:
1132 UNREACHABLE();
1133 }
1134}
1135
1136
1137void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
1138 // Nothing to do.
1139}
1140
1141
1142void LCodeGen::DoModI(LModI* instr) {
1143 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001144 const Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001145 const Register result = ToRegister(instr->result());
1146
erikcorry0ad885c2011-11-21 13:51:57 +00001147 Label done;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001148
erikcorry0ad885c2011-11-21 13:51:57 +00001149 if (instr->hydrogen()->HasPowerOf2Divisor()) {
1150 Register scratch = scratch0();
1151 ASSERT(!left.is(scratch));
1152 __ mov(scratch, left);
1153 int32_t p2constant = HConstant::cast(
1154 instr->hydrogen()->right())->Integer32Value();
1155 ASSERT(p2constant != 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001156 // Result always takes the sign of the dividend (left).
erikcorry0ad885c2011-11-21 13:51:57 +00001157 p2constant = abs(p2constant);
1158
1159 Label positive_dividend;
1160 __ Branch(USE_DELAY_SLOT, &positive_dividend, ge, left, Operand(zero_reg));
1161 __ subu(result, zero_reg, left);
1162 __ And(result, result, p2constant - 1);
1163 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1164 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
1165 }
1166 __ Branch(USE_DELAY_SLOT, &done);
1167 __ subu(result, zero_reg, result);
1168 __ bind(&positive_dividend);
1169 __ And(result, scratch, p2constant - 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001170 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00001171 // div runs in the background while we check for special cases.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001172 Register right = EmitLoadRegister(instr->right(), scratch);
erikcorry0ad885c2011-11-21 13:51:57 +00001173 __ div(left, right);
1174
1175 // Check for x % 0.
1176 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1177 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1178 }
1179
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001180 // Check for (kMinInt % -1).
1181 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1182 Label left_not_min_int;
1183 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1184 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1185 __ bind(&left_not_min_int);
1186 }
1187
erikcorry0ad885c2011-11-21 13:51:57 +00001188 __ Branch(USE_DELAY_SLOT, &done, ge, left, Operand(zero_reg));
1189 __ mfhi(result);
1190
1191 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1192 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
1193 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001194 }
erikcorry0ad885c2011-11-21 13:51:57 +00001195 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001196}
1197
1198
1199void LCodeGen::DoDivI(LDivI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001200 const Register left = ToRegister(instr->left());
1201 const Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001202 const Register result = ToRegister(instr->result());
1203
1204 // On MIPS div is asynchronous - it will run in the background while we
1205 // check for special cases.
1206 __ div(left, right);
1207
1208 // Check for x / 0.
1209 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1210 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1211 }
1212
1213 // Check for (0 / -x) that will produce negative zero.
1214 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1215 Label left_not_zero;
1216 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1217 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1218 __ bind(&left_not_zero);
1219 }
1220
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001221 // Check for (kMinInt / -1).
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001222 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1223 Label left_not_min_int;
1224 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1225 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1226 __ bind(&left_not_min_int);
1227 }
1228
1229 __ mfhi(result);
1230 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg));
1231 __ mflo(result);
1232}
1233
1234
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001235void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
1236 DoubleRegister addend = ToDoubleRegister(instr->addend());
1237 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
1238 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
1239
1240 // This is computed in-place.
1241 ASSERT(addend.is(ToDoubleRegister(instr->result())));
1242
1243 __ madd_d(addend, addend, multiplier, multiplicand);
1244}
1245
1246
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001247void LCodeGen::DoMulI(LMulI* instr) {
1248 Register scratch = scratch0();
1249 Register result = ToRegister(instr->result());
1250 // Note that result may alias left.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001251 Register left = ToRegister(instr->left());
1252 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001253
1254 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1255 bool bailout_on_minus_zero =
1256 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
1257
1258 if (right_op->IsConstantOperand() && !can_overflow) {
1259 // Use optimized code for specific constants.
1260 int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
1261
1262 if (bailout_on_minus_zero && (constant < 0)) {
1263 // The case of a null constant will be handled separately.
1264 // If constant is negative and left is null, the result should be -0.
1265 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1266 }
1267
1268 switch (constant) {
1269 case -1:
1270 __ Subu(result, zero_reg, left);
1271 break;
1272 case 0:
1273 if (bailout_on_minus_zero) {
1274 // If left is strictly negative and the constant is null, the
1275 // result is -0. Deoptimize if required, otherwise return 0.
1276 DeoptimizeIf(lt, instr->environment(), left, Operand(zero_reg));
1277 }
1278 __ mov(result, zero_reg);
1279 break;
1280 case 1:
1281 // Nothing to do.
1282 __ Move(result, left);
1283 break;
1284 default:
1285 // Multiplying by powers of two and powers of two plus or minus
1286 // one can be done faster with shifted operands.
1287 // For other constants we emit standard code.
1288 int32_t mask = constant >> 31;
1289 uint32_t constant_abs = (constant + mask) ^ mask;
1290
1291 if (IsPowerOf2(constant_abs) ||
1292 IsPowerOf2(constant_abs - 1) ||
1293 IsPowerOf2(constant_abs + 1)) {
1294 if (IsPowerOf2(constant_abs)) {
1295 int32_t shift = WhichPowerOf2(constant_abs);
1296 __ sll(result, left, shift);
1297 } else if (IsPowerOf2(constant_abs - 1)) {
1298 int32_t shift = WhichPowerOf2(constant_abs - 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001299 __ sll(scratch, left, shift);
1300 __ Addu(result, scratch, left);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001301 } else if (IsPowerOf2(constant_abs + 1)) {
1302 int32_t shift = WhichPowerOf2(constant_abs + 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001303 __ sll(scratch, left, shift);
1304 __ Subu(result, scratch, left);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001305 }
1306
1307 // Correct the sign of the result is the constant is negative.
1308 if (constant < 0) {
1309 __ Subu(result, zero_reg, result);
1310 }
1311
1312 } else {
1313 // Generate standard code.
1314 __ li(at, constant);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001315 __ Mul(result, left, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001316 }
1317 }
1318
1319 } else {
1320 Register right = EmitLoadRegister(right_op, scratch);
1321 if (bailout_on_minus_zero) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001322 __ Or(ToRegister(instr->temp()), left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001323 }
1324
1325 if (can_overflow) {
1326 // hi:lo = left * right.
1327 __ mult(left, right);
1328 __ mfhi(scratch);
1329 __ mflo(result);
1330 __ sra(at, result, 31);
1331 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
1332 } else {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001333 __ Mul(result, left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001334 }
1335
1336 if (bailout_on_minus_zero) {
1337 // Bail out if the result is supposed to be negative zero.
1338 Label done;
1339 __ Branch(&done, ne, result, Operand(zero_reg));
1340 DeoptimizeIf(lt,
1341 instr->environment(),
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001342 ToRegister(instr->temp()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001343 Operand(zero_reg));
1344 __ bind(&done);
1345 }
1346 }
1347}
1348
1349
1350void LCodeGen::DoBitI(LBitI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001351 LOperand* left_op = instr->left();
1352 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001353 ASSERT(left_op->IsRegister());
1354 Register left = ToRegister(left_op);
1355 Register result = ToRegister(instr->result());
1356 Operand right(no_reg);
1357
1358 if (right_op->IsStackSlot() || right_op->IsArgument()) {
1359 right = Operand(EmitLoadRegister(right_op, at));
1360 } else {
1361 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
1362 right = ToOperand(right_op);
1363 }
1364
1365 switch (instr->op()) {
1366 case Token::BIT_AND:
1367 __ And(result, left, right);
1368 break;
1369 case Token::BIT_OR:
1370 __ Or(result, left, right);
1371 break;
1372 case Token::BIT_XOR:
1373 __ Xor(result, left, right);
1374 break;
1375 default:
1376 UNREACHABLE();
1377 break;
1378 }
1379}
1380
1381
1382void LCodeGen::DoShiftI(LShiftI* instr) {
1383 // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
1384 // result may alias either of them.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001385 LOperand* right_op = instr->right();
1386 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001387 Register result = ToRegister(instr->result());
1388
1389 if (right_op->IsRegister()) {
1390 // No need to mask the right operand on MIPS, it is built into the variable
1391 // shift instructions.
1392 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001393 case Token::ROR:
1394 __ Ror(result, left, Operand(ToRegister(right_op)));
1395 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001396 case Token::SAR:
1397 __ srav(result, left, ToRegister(right_op));
1398 break;
1399 case Token::SHR:
1400 __ srlv(result, left, ToRegister(right_op));
1401 if (instr->can_deopt()) {
1402 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
1403 }
1404 break;
1405 case Token::SHL:
1406 __ sllv(result, left, ToRegister(right_op));
1407 break;
1408 default:
1409 UNREACHABLE();
1410 break;
1411 }
1412 } else {
1413 // Mask the right_op operand.
1414 int value = ToInteger32(LConstantOperand::cast(right_op));
1415 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1416 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001417 case Token::ROR:
1418 if (shift_count != 0) {
1419 __ Ror(result, left, Operand(shift_count));
1420 } else {
1421 __ Move(result, left);
1422 }
1423 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001424 case Token::SAR:
1425 if (shift_count != 0) {
1426 __ sra(result, left, shift_count);
1427 } else {
1428 __ Move(result, left);
1429 }
1430 break;
1431 case Token::SHR:
1432 if (shift_count != 0) {
1433 __ srl(result, left, shift_count);
1434 } else {
1435 if (instr->can_deopt()) {
1436 __ And(at, left, Operand(0x80000000));
1437 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
1438 }
1439 __ Move(result, left);
1440 }
1441 break;
1442 case Token::SHL:
1443 if (shift_count != 0) {
1444 __ sll(result, left, shift_count);
1445 } else {
1446 __ Move(result, left);
1447 }
1448 break;
1449 default:
1450 UNREACHABLE();
1451 break;
1452 }
1453 }
1454}
1455
1456
1457void LCodeGen::DoSubI(LSubI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001458 LOperand* left = instr->left();
1459 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001460 LOperand* result = instr->result();
1461 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1462
1463 if (!can_overflow) {
1464 if (right->IsStackSlot() || right->IsArgument()) {
1465 Register right_reg = EmitLoadRegister(right, at);
1466 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg));
1467 } else {
1468 ASSERT(right->IsRegister() || right->IsConstantOperand());
1469 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
1470 }
1471 } else { // can_overflow.
1472 Register overflow = scratch0();
1473 Register scratch = scratch1();
1474 if (right->IsStackSlot() ||
1475 right->IsArgument() ||
1476 right->IsConstantOperand()) {
1477 Register right_reg = EmitLoadRegister(right, scratch);
1478 __ SubuAndCheckForOverflow(ToRegister(result),
1479 ToRegister(left),
1480 right_reg,
1481 overflow); // Reg at also used as scratch.
1482 } else {
1483 ASSERT(right->IsRegister());
1484 // Due to overflow check macros not supporting constant operands,
1485 // handling the IsConstantOperand case was moved to prev if clause.
1486 __ SubuAndCheckForOverflow(ToRegister(result),
1487 ToRegister(left),
1488 ToRegister(right),
1489 overflow); // Reg at also used as scratch.
1490 }
1491 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1492 }
1493}
1494
1495
1496void LCodeGen::DoConstantI(LConstantI* instr) {
1497 ASSERT(instr->result()->IsRegister());
1498 __ li(ToRegister(instr->result()), Operand(instr->value()));
1499}
1500
1501
1502void LCodeGen::DoConstantD(LConstantD* instr) {
1503 ASSERT(instr->result()->IsDoubleRegister());
1504 DoubleRegister result = ToDoubleRegister(instr->result());
1505 double v = instr->value();
1506 __ Move(result, v);
1507}
1508
1509
1510void LCodeGen::DoConstantT(LConstantT* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001511 Handle<Object> value = instr->value();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001512 ALLOW_HANDLE_DEREF(isolate(), "smi check");
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001513 if (value->IsSmi()) {
1514 __ li(ToRegister(instr->result()), Operand(value));
1515 } else {
1516 __ LoadHeapObject(ToRegister(instr->result()),
1517 Handle<HeapObject>::cast(value));
1518 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001519}
1520
1521
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001522void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
1523 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001524 Register array = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001525 __ lw(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
1526}
1527
1528
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001529void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1530 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001531 Register map = ToRegister(instr->value());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001532 __ EnumLength(result, map);
1533}
1534
1535
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001536void LCodeGen::DoElementsKind(LElementsKind* instr) {
1537 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001538 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001539
1540 // Load map into |result|.
1541 __ lw(result, FieldMemOperand(input, HeapObject::kMapOffset));
1542 // Load the map's "bit field 2" into |result|. We only need the first byte,
1543 // but the following bit field extraction takes care of that anyway.
1544 __ lbu(result, FieldMemOperand(result, Map::kBitField2Offset));
1545 // Retrieve elements_kind from bit field 2.
1546 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
1547}
1548
1549
1550void LCodeGen::DoValueOf(LValueOf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001551 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001552 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001553 Register map = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001554 Label done;
1555
1556 // If the object is a smi return the object.
1557 __ Move(result, input);
1558 __ JumpIfSmi(input, &done);
1559
1560 // If the object is not a value type, return the object.
1561 __ GetObjectType(input, map, map);
1562 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE));
1563 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset));
1564
1565 __ bind(&done);
1566}
1567
1568
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001569void LCodeGen::DoDateField(LDateField* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001570 Register object = ToRegister(instr->date());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001571 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001572 Register scratch = ToRegister(instr->temp());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001573 Smi* index = instr->index();
1574 Label runtime, done;
1575 ASSERT(object.is(a0));
1576 ASSERT(result.is(v0));
1577 ASSERT(!scratch.is(scratch0()));
1578 ASSERT(!scratch.is(object));
1579
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001580 __ And(at, object, Operand(kSmiTagMask));
1581 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001582 __ GetObjectType(object, scratch, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001583 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001584
1585 if (index->value() == 0) {
1586 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
1587 } else {
1588 if (index->value() < JSDate::kFirstUncachedField) {
1589 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1590 __ li(scratch, Operand(stamp));
1591 __ lw(scratch, MemOperand(scratch));
1592 __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
1593 __ Branch(&runtime, ne, scratch, Operand(scratch0()));
1594 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
1595 kPointerSize * index->value()));
1596 __ jmp(&done);
1597 }
1598 __ bind(&runtime);
1599 __ PrepareCallCFunction(2, scratch);
1600 __ li(a1, Operand(index));
1601 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1602 __ bind(&done);
1603 }
1604}
1605
1606
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001607void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001608 Register string = ToRegister(instr->string());
1609 Register index = ToRegister(instr->index());
1610 Register value = ToRegister(instr->value());
1611 Register scratch = scratch0();
1612 String::Encoding encoding = instr->encoding();
1613
1614 if (FLAG_debug_code) {
1615 __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
1616 __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
1617
1618 __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask));
1619 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1620 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1621 __ Subu(at, at, Operand(encoding == String::ONE_BYTE_ENCODING
1622 ? one_byte_seq_type : two_byte_seq_type));
1623 __ Check(eq, "Unexpected string type", at, Operand(zero_reg));
1624 }
1625
1626 __ Addu(scratch,
1627 string,
1628 Operand(SeqString::kHeaderSize - kHeapObjectTag));
1629 if (encoding == String::ONE_BYTE_ENCODING) {
1630 __ Addu(at, scratch, index);
1631 __ sb(value, MemOperand(at));
1632 } else {
1633 __ sll(at, index, 1);
1634 __ Addu(at, scratch, at);
1635 __ sh(value, MemOperand(at));
1636 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001637}
1638
1639
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001640void LCodeGen::DoBitNotI(LBitNotI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001641 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001642 Register result = ToRegister(instr->result());
1643 __ Nor(result, zero_reg, Operand(input));
1644}
1645
1646
1647void LCodeGen::DoThrow(LThrow* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001648 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649 __ push(input_reg);
1650 CallRuntime(Runtime::kThrow, 1, instr);
1651
1652 if (FLAG_debug_code) {
1653 __ stop("Unreachable code.");
1654 }
1655}
1656
1657
1658void LCodeGen::DoAddI(LAddI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001659 LOperand* left = instr->left();
1660 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001661 LOperand* result = instr->result();
1662 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1663
1664 if (!can_overflow) {
1665 if (right->IsStackSlot() || right->IsArgument()) {
1666 Register right_reg = EmitLoadRegister(right, at);
1667 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg));
1668 } else {
1669 ASSERT(right->IsRegister() || right->IsConstantOperand());
1670 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
1671 }
1672 } else { // can_overflow.
1673 Register overflow = scratch0();
1674 Register scratch = scratch1();
1675 if (right->IsStackSlot() ||
1676 right->IsArgument() ||
1677 right->IsConstantOperand()) {
1678 Register right_reg = EmitLoadRegister(right, scratch);
1679 __ AdduAndCheckForOverflow(ToRegister(result),
1680 ToRegister(left),
1681 right_reg,
1682 overflow); // Reg at also used as scratch.
1683 } else {
1684 ASSERT(right->IsRegister());
1685 // Due to overflow check macros not supporting constant operands,
1686 // handling the IsConstantOperand case was moved to prev if clause.
1687 __ AdduAndCheckForOverflow(ToRegister(result),
1688 ToRegister(left),
1689 ToRegister(right),
1690 overflow); // Reg at also used as scratch.
1691 }
1692 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1693 }
1694}
1695
1696
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001697void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001698 LOperand* left = instr->left();
1699 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001700 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1701 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
1702 if (instr->hydrogen()->representation().IsInteger32()) {
1703 Register left_reg = ToRegister(left);
1704 Operand right_op = (right->IsRegister() || right->IsConstantOperand())
1705 ? ToOperand(right)
1706 : Operand(EmitLoadRegister(right, at));
1707 Register result_reg = ToRegister(instr->result());
1708 Label return_right, done;
1709 if (!result_reg.is(left_reg)) {
1710 __ Branch(&return_right, NegateCondition(condition), left_reg, right_op);
1711 __ mov(result_reg, left_reg);
1712 __ Branch(&done);
1713 }
1714 __ Branch(&done, condition, left_reg, right_op);
1715 __ bind(&return_right);
1716 __ Addu(result_reg, zero_reg, right_op);
1717 __ bind(&done);
1718 } else {
1719 ASSERT(instr->hydrogen()->representation().IsDouble());
1720 FPURegister left_reg = ToDoubleRegister(left);
1721 FPURegister right_reg = ToDoubleRegister(right);
1722 FPURegister result_reg = ToDoubleRegister(instr->result());
1723 Label check_nan_left, check_zero, return_left, return_right, done;
1724 __ BranchF(&check_zero, &check_nan_left, eq, left_reg, right_reg);
1725 __ BranchF(&return_left, NULL, condition, left_reg, right_reg);
1726 __ Branch(&return_right);
1727
1728 __ bind(&check_zero);
1729 // left == right != 0.
1730 __ BranchF(&return_left, NULL, ne, left_reg, kDoubleRegZero);
1731 // At this point, both left and right are either 0 or -0.
1732 if (operation == HMathMinMax::kMathMin) {
1733 __ neg_d(left_reg, left_reg);
1734 __ sub_d(result_reg, left_reg, right_reg);
1735 __ neg_d(result_reg, result_reg);
1736 } else {
1737 __ add_d(result_reg, left_reg, right_reg);
1738 }
1739 __ Branch(&done);
1740
1741 __ bind(&check_nan_left);
1742 // left == NaN.
1743 __ BranchF(NULL, &return_left, eq, left_reg, left_reg);
1744 __ bind(&return_right);
1745 if (!right_reg.is(result_reg)) {
1746 __ mov_d(result_reg, right_reg);
1747 }
1748 __ Branch(&done);
1749
1750 __ bind(&return_left);
1751 if (!left_reg.is(result_reg)) {
1752 __ mov_d(result_reg, left_reg);
1753 }
1754 __ bind(&done);
1755 }
1756}
1757
1758
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001759void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001760 DoubleRegister left = ToDoubleRegister(instr->left());
1761 DoubleRegister right = ToDoubleRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001762 DoubleRegister result = ToDoubleRegister(instr->result());
1763 switch (instr->op()) {
1764 case Token::ADD:
1765 __ add_d(result, left, right);
1766 break;
1767 case Token::SUB:
1768 __ sub_d(result, left, right);
1769 break;
1770 case Token::MUL:
1771 __ mul_d(result, left, right);
1772 break;
1773 case Token::DIV:
1774 __ div_d(result, left, right);
1775 break;
1776 case Token::MOD: {
1777 // Save a0-a3 on the stack.
1778 RegList saved_regs = a0.bit() | a1.bit() | a2.bit() | a3.bit();
1779 __ MultiPush(saved_regs);
1780
1781 __ PrepareCallCFunction(0, 2, scratch0());
1782 __ SetCallCDoubleArguments(left, right);
1783 __ CallCFunction(
1784 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1785 0, 2);
1786 // Move the result in the double result register.
1787 __ GetCFunctionDoubleResult(result);
1788
1789 // Restore saved register.
1790 __ MultiPop(saved_regs);
1791 break;
1792 }
1793 default:
1794 UNREACHABLE();
1795 break;
1796 }
1797}
1798
1799
1800void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001801 ASSERT(ToRegister(instr->left()).is(a1));
1802 ASSERT(ToRegister(instr->right()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001803 ASSERT(ToRegister(instr->result()).is(v0));
1804
1805 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001806 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001807 // Other arch use a nop here, to signal that there is no inlined
1808 // patchable code. Mips does not need the nop, since our marker
1809 // instruction (andi zero_reg) will never be used in normal code.
1810}
1811
1812
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001813int LCodeGen::GetNextEmittedBlock() const {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001814 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
1815 if (!chunk_->GetLabel(i)->HasReplacement()) return i;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001816 }
1817 return -1;
1818}
1819
1820
1821void LCodeGen::EmitBranch(int left_block, int right_block,
1822 Condition cc, Register src1, const Operand& src2) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001823 int next_block = GetNextEmittedBlock();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001824 right_block = chunk_->LookupDestination(right_block);
1825 left_block = chunk_->LookupDestination(left_block);
1826 if (right_block == left_block) {
1827 EmitGoto(left_block);
1828 } else if (left_block == next_block) {
1829 __ Branch(chunk_->GetAssemblyLabel(right_block),
1830 NegateCondition(cc), src1, src2);
1831 } else if (right_block == next_block) {
1832 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2);
1833 } else {
1834 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2);
1835 __ Branch(chunk_->GetAssemblyLabel(right_block));
1836 }
1837}
1838
1839
1840void LCodeGen::EmitBranchF(int left_block, int right_block,
1841 Condition cc, FPURegister src1, FPURegister src2) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001842 int next_block = GetNextEmittedBlock();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001843 right_block = chunk_->LookupDestination(right_block);
1844 left_block = chunk_->LookupDestination(left_block);
1845 if (right_block == left_block) {
1846 EmitGoto(left_block);
1847 } else if (left_block == next_block) {
1848 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL,
1849 NegateCondition(cc), src1, src2);
1850 } else if (right_block == next_block) {
1851 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2);
1852 } else {
1853 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2);
1854 __ Branch(chunk_->GetAssemblyLabel(right_block));
1855 }
1856}
1857
1858
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001859void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1860 __ stop("LDebugBreak");
1861}
1862
1863
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001864void LCodeGen::DoBranch(LBranch* instr) {
1865 int true_block = chunk_->LookupDestination(instr->true_block_id());
1866 int false_block = chunk_->LookupDestination(instr->false_block_id());
1867
1868 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001869 if (r.IsInteger32() || r.IsSmi()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001870 Register reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001871 EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
1872 } else if (r.IsDouble()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001873 DoubleRegister reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001874 // Test the double value. Zero and NaN are false.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001875 EmitBranchF(true_block, false_block, nue, reg, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001876 } else {
1877 ASSERT(r.IsTagged());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001878 Register reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001879 HType type = instr->hydrogen()->value()->type();
1880 if (type.IsBoolean()) {
1881 __ LoadRoot(at, Heap::kTrueValueRootIndex);
1882 EmitBranch(true_block, false_block, eq, reg, Operand(at));
1883 } else if (type.IsSmi()) {
1884 EmitBranch(true_block, false_block, ne, reg, Operand(zero_reg));
1885 } else {
1886 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1887 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1888
1889 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
1890 // Avoid deopts in the case where we've never executed this path before.
1891 if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
1892
1893 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
1894 // undefined -> false.
1895 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1896 __ Branch(false_label, eq, reg, Operand(at));
1897 }
1898 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
1899 // Boolean -> its value.
1900 __ LoadRoot(at, Heap::kTrueValueRootIndex);
1901 __ Branch(true_label, eq, reg, Operand(at));
1902 __ LoadRoot(at, Heap::kFalseValueRootIndex);
1903 __ Branch(false_label, eq, reg, Operand(at));
1904 }
1905 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
1906 // 'null' -> false.
1907 __ LoadRoot(at, Heap::kNullValueRootIndex);
1908 __ Branch(false_label, eq, reg, Operand(at));
1909 }
1910
1911 if (expected.Contains(ToBooleanStub::SMI)) {
1912 // Smis: 0 -> false, all other -> true.
1913 __ Branch(false_label, eq, reg, Operand(zero_reg));
1914 __ JumpIfSmi(reg, true_label);
1915 } else if (expected.NeedsMap()) {
1916 // If we need a map later and have a Smi -> deopt.
1917 __ And(at, reg, Operand(kSmiTagMask));
1918 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
1919 }
1920
1921 const Register map = scratch0();
1922 if (expected.NeedsMap()) {
1923 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset));
1924 if (expected.CanBeUndetectable()) {
1925 // Undetectable -> false.
1926 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
1927 __ And(at, at, Operand(1 << Map::kIsUndetectable));
1928 __ Branch(false_label, ne, at, Operand(zero_reg));
1929 }
1930 }
1931
1932 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
1933 // spec object -> true.
1934 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
1935 __ Branch(true_label, ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
1936 }
1937
1938 if (expected.Contains(ToBooleanStub::STRING)) {
1939 // String value -> false iff empty.
1940 Label not_string;
1941 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
1942 __ Branch(&not_string, ge , at, Operand(FIRST_NONSTRING_TYPE));
1943 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
1944 __ Branch(true_label, ne, at, Operand(zero_reg));
1945 __ Branch(false_label);
1946 __ bind(&not_string);
1947 }
1948
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001949 if (expected.Contains(ToBooleanStub::SYMBOL)) {
1950 // Symbol value -> true.
1951 const Register scratch = scratch1();
1952 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
1953 __ Branch(true_label, eq, scratch, Operand(SYMBOL_TYPE));
1954 }
1955
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001956 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
1957 // heap number -> false iff +0, -0, or NaN.
1958 DoubleRegister dbl_scratch = double_scratch0();
1959 Label not_heap_number;
1960 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1961 __ Branch(&not_heap_number, ne, map, Operand(at));
1962 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
1963 __ BranchF(true_label, false_label, ne, dbl_scratch, kDoubleRegZero);
1964 // Falls through if dbl_scratch == 0.
1965 __ Branch(false_label);
1966 __ bind(&not_heap_number);
1967 }
1968
1969 // We've seen something for the first time -> deopt.
1970 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
1971 }
1972 }
1973}
1974
1975
1976void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001977 if (!IsNextEmittedBlock(block)) {
1978 __ jmp(chunk_->GetAssemblyLabel(chunk_->LookupDestination(block)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001979 }
1980}
1981
1982
1983void LCodeGen::DoGoto(LGoto* instr) {
1984 EmitGoto(instr->block_id());
1985}
1986
1987
1988Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
1989 Condition cond = kNoCondition;
1990 switch (op) {
1991 case Token::EQ:
1992 case Token::EQ_STRICT:
1993 cond = eq;
1994 break;
1995 case Token::LT:
1996 cond = is_unsigned ? lo : lt;
1997 break;
1998 case Token::GT:
1999 cond = is_unsigned ? hi : gt;
2000 break;
2001 case Token::LTE:
2002 cond = is_unsigned ? ls : le;
2003 break;
2004 case Token::GTE:
2005 cond = is_unsigned ? hs : ge;
2006 break;
2007 case Token::IN:
2008 case Token::INSTANCEOF:
2009 default:
2010 UNREACHABLE();
2011 }
2012 return cond;
2013}
2014
2015
2016void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002017 LOperand* left = instr->left();
2018 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002019 int false_block = chunk_->LookupDestination(instr->false_block_id());
2020 int true_block = chunk_->LookupDestination(instr->true_block_id());
2021
2022 Condition cond = TokenToCondition(instr->op(), false);
2023
2024 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2025 // We can statically evaluate the comparison.
2026 double left_val = ToDouble(LConstantOperand::cast(left));
2027 double right_val = ToDouble(LConstantOperand::cast(right));
2028 int next_block =
2029 EvalComparison(instr->op(), left_val, right_val) ? true_block
2030 : false_block;
2031 EmitGoto(next_block);
2032 } else {
2033 if (instr->is_double()) {
2034 // Compare left and right as doubles and load the
2035 // resulting flags into the normal status register.
2036 FPURegister left_reg = ToDoubleRegister(left);
2037 FPURegister right_reg = ToDoubleRegister(right);
2038
2039 // If a NaN is involved, i.e. the result is unordered,
2040 // jump to false block label.
2041 __ BranchF(NULL, chunk_->GetAssemblyLabel(false_block), eq,
2042 left_reg, right_reg);
2043
2044 EmitBranchF(true_block, false_block, cond, left_reg, right_reg);
2045 } else {
2046 Register cmp_left;
2047 Operand cmp_right = Operand(0);
2048
2049 if (right->IsConstantOperand()) {
2050 cmp_left = ToRegister(left);
2051 cmp_right = Operand(ToInteger32(LConstantOperand::cast(right)));
2052 } else if (left->IsConstantOperand()) {
2053 cmp_left = ToRegister(right);
2054 cmp_right = Operand(ToInteger32(LConstantOperand::cast(left)));
2055 // We transposed the operands. Reverse the condition.
2056 cond = ReverseCondition(cond);
2057 } else {
2058 cmp_left = ToRegister(left);
2059 cmp_right = Operand(ToRegister(right));
2060 }
2061
2062 EmitBranch(true_block, false_block, cond, cmp_left, cmp_right);
2063 }
2064 }
2065}
2066
2067
2068void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002069 Register left = ToRegister(instr->left());
2070 Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002071 int false_block = chunk_->LookupDestination(instr->false_block_id());
2072 int true_block = chunk_->LookupDestination(instr->true_block_id());
2073
2074 EmitBranch(true_block, false_block, eq, left, Operand(right));
2075}
2076
2077
2078void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002079 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002080 int true_block = chunk_->LookupDestination(instr->true_block_id());
2081 int false_block = chunk_->LookupDestination(instr->false_block_id());
2082
2083 EmitBranch(true_block, false_block, eq, left,
2084 Operand(instr->hydrogen()->right()));
2085}
2086
2087
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002088Condition LCodeGen::EmitIsObject(Register input,
2089 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +00002090 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002091 Label* is_not_object,
2092 Label* is_object) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002093 __ JumpIfSmi(input, is_not_object);
2094
2095 __ LoadRoot(temp2, Heap::kNullValueRootIndex);
2096 __ Branch(is_object, eq, input, Operand(temp2));
2097
2098 // Load map.
2099 __ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
2100 // Undetectable objects behave like undefined.
2101 __ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
2102 __ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
2103 __ Branch(is_not_object, ne, temp2, Operand(zero_reg));
2104
2105 // Load instance type and check that it is in object type range.
2106 __ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
2107 __ Branch(is_not_object,
2108 lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2109
2110 return le;
2111}
2112
2113
2114void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002115 Register reg = ToRegister(instr->value());
2116 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002117 Register temp2 = scratch0();
2118
2119 int true_block = chunk_->LookupDestination(instr->true_block_id());
2120 int false_block = chunk_->LookupDestination(instr->false_block_id());
2121 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2122 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2123
2124 Condition true_cond =
erikcorry0ad885c2011-11-21 13:51:57 +00002125 EmitIsObject(reg, temp1, temp2, false_label, true_label);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126
2127 EmitBranch(true_block, false_block, true_cond, temp2,
2128 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2129}
2130
2131
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002132Condition LCodeGen::EmitIsString(Register input,
2133 Register temp1,
2134 Label* is_not_string) {
2135 __ JumpIfSmi(input, is_not_string);
2136 __ GetObjectType(input, temp1, temp1);
2137
2138 return lt;
2139}
2140
2141
2142void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002143 Register reg = ToRegister(instr->value());
2144 Register temp1 = ToRegister(instr->temp());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002145
2146 int true_block = chunk_->LookupDestination(instr->true_block_id());
2147 int false_block = chunk_->LookupDestination(instr->false_block_id());
2148 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2149
2150 Condition true_cond =
2151 EmitIsString(reg, temp1, false_label);
2152
2153 EmitBranch(true_block, false_block, true_cond, temp1,
2154 Operand(FIRST_NONSTRING_TYPE));
2155}
2156
2157
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002158void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
2159 int true_block = chunk_->LookupDestination(instr->true_block_id());
2160 int false_block = chunk_->LookupDestination(instr->false_block_id());
2161
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002162 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002163 __ And(at, input_reg, kSmiTagMask);
2164 EmitBranch(true_block, false_block, eq, at, Operand(zero_reg));
2165}
2166
2167
2168void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002169 Register input = ToRegister(instr->value());
2170 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171
2172 int true_block = chunk_->LookupDestination(instr->true_block_id());
2173 int false_block = chunk_->LookupDestination(instr->false_block_id());
2174
2175 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
2176 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset));
2177 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
2178 __ And(at, temp, Operand(1 << Map::kIsUndetectable));
2179 EmitBranch(true_block, false_block, ne, at, Operand(zero_reg));
2180}
2181
2182
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002183static Condition ComputeCompareCondition(Token::Value op) {
2184 switch (op) {
2185 case Token::EQ_STRICT:
2186 case Token::EQ:
2187 return eq;
2188 case Token::LT:
2189 return lt;
2190 case Token::GT:
2191 return gt;
2192 case Token::LTE:
2193 return le;
2194 case Token::GTE:
2195 return ge;
2196 default:
2197 UNREACHABLE();
2198 return kNoCondition;
2199 }
2200}
2201
2202
2203void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2204 Token::Value op = instr->op();
2205 int true_block = chunk_->LookupDestination(instr->true_block_id());
2206 int false_block = chunk_->LookupDestination(instr->false_block_id());
2207
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002208 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002209 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2210
2211 Condition condition = ComputeCompareCondition(op);
2212
2213 EmitBranch(true_block, false_block, condition, v0, Operand(zero_reg));
2214}
2215
2216
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2218 InstanceType from = instr->from();
2219 InstanceType to = instr->to();
2220 if (from == FIRST_TYPE) return to;
2221 ASSERT(from == to || to == LAST_TYPE);
2222 return from;
2223}
2224
2225
2226static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2227 InstanceType from = instr->from();
2228 InstanceType to = instr->to();
2229 if (from == to) return eq;
2230 if (to == LAST_TYPE) return hs;
2231 if (from == FIRST_TYPE) return ls;
2232 UNREACHABLE();
2233 return eq;
2234}
2235
2236
2237void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2238 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002239 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002240
2241 int true_block = chunk_->LookupDestination(instr->true_block_id());
2242 int false_block = chunk_->LookupDestination(instr->false_block_id());
2243
2244 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2245
2246 __ JumpIfSmi(input, false_label);
2247
2248 __ GetObjectType(input, scratch, scratch);
2249 EmitBranch(true_block,
2250 false_block,
2251 BranchCondition(instr->hydrogen()),
2252 scratch,
2253 Operand(TestType(instr->hydrogen())));
2254}
2255
2256
2257void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002258 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 Register result = ToRegister(instr->result());
2260
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002261 __ AssertString(input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002262
2263 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset));
2264 __ IndexFromHash(result, result);
2265}
2266
2267
2268void LCodeGen::DoHasCachedArrayIndexAndBranch(
2269 LHasCachedArrayIndexAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002270 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002271 Register scratch = scratch0();
2272
2273 int true_block = chunk_->LookupDestination(instr->true_block_id());
2274 int false_block = chunk_->LookupDestination(instr->false_block_id());
2275
2276 __ lw(scratch,
2277 FieldMemOperand(input, String::kHashFieldOffset));
2278 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask));
2279 EmitBranch(true_block, false_block, eq, at, Operand(zero_reg));
2280}
2281
2282
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002283// Branches to a label or falls through with the answer in flags. Trashes
2284// the temp registers, but not the input.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285void LCodeGen::EmitClassOfTest(Label* is_true,
2286 Label* is_false,
2287 Handle<String>class_name,
2288 Register input,
2289 Register temp,
2290 Register temp2) {
2291 ASSERT(!input.is(temp));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002292 ASSERT(!input.is(temp2));
2293 ASSERT(!temp.is(temp2));
2294
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002295 __ JumpIfSmi(input, is_false);
2296
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002297 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002298 // Assuming the following assertions, we can use the same compares to test
2299 // for both being a function type and being in the object type range.
2300 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2301 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2302 FIRST_SPEC_OBJECT_TYPE + 1);
2303 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2304 LAST_SPEC_OBJECT_TYPE - 1);
2305 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2306
2307 __ GetObjectType(input, temp, temp2);
2308 __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2309 __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2310 __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
2311 } else {
2312 // Faster code path to avoid two compares: subtract lower bound from the
2313 // actual type and do a signed compare with the width of the type range.
2314 __ GetObjectType(input, temp, temp2);
2315 __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2316 __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2317 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2318 }
2319
2320 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2321 // Check if the constructor in the map is a function.
2322 __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset));
2323
2324 // Objects with a non-function constructor have class 'Object'.
2325 __ GetObjectType(temp, temp2, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002326 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002327 __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
2328 } else {
2329 __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
2330 }
2331
2332 // temp now contains the constructor function. Grab the
2333 // instance class name from there.
2334 __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2335 __ lw(temp, FieldMemOperand(temp,
2336 SharedFunctionInfo::kInstanceClassNameOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002337 // The class name we are testing against is internalized since it's a literal.
2338 // The name in the constructor is internalized because of the way the context
2339 // is booted. This routine isn't expected to work for random API-created
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002340 // classes and it doesn't have to because you can't access it with natives
ulan@chromium.org750145a2013-03-07 15:14:13 +00002341 // syntax. Since both sides are internalized it is sufficient to use an
2342 // identity comparison.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002343
2344 // End with the address of this class_name instance in temp register.
2345 // On MIPS, the caller must do the comparison with Handle<String>class_name.
2346}
2347
2348
2349void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002350 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002351 Register temp = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002352 Register temp2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002353 Handle<String> class_name = instr->hydrogen()->class_name();
2354
2355 int true_block = chunk_->LookupDestination(instr->true_block_id());
2356 int false_block = chunk_->LookupDestination(instr->false_block_id());
2357
2358 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2359 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2360
2361 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2362
2363 EmitBranch(true_block, false_block, eq, temp, Operand(class_name));
2364}
2365
2366
2367void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002368 Register reg = ToRegister(instr->value());
2369 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002370 int true_block = instr->true_block_id();
2371 int false_block = instr->false_block_id();
2372
2373 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
2374 EmitBranch(true_block, false_block, eq, temp, Operand(instr->map()));
2375}
2376
2377
2378void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
2379 Label true_label, done;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002380 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0.
2381 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002382 Register result = ToRegister(instr->result());
2383 ASSERT(result.is(v0));
2384
2385 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002386 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002387
2388 __ Branch(&true_label, eq, result, Operand(zero_reg));
2389 __ li(result, Operand(factory()->false_value()));
2390 __ Branch(&done);
2391 __ bind(&true_label);
2392 __ li(result, Operand(factory()->true_value()));
2393 __ bind(&done);
2394}
2395
2396
2397void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2398 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2399 public:
2400 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2401 LInstanceOfKnownGlobal* instr)
2402 : LDeferredCode(codegen), instr_(instr) { }
2403 virtual void Generate() {
erikcorry0ad885c2011-11-21 13:51:57 +00002404 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002405 }
2406 virtual LInstruction* instr() { return instr_; }
2407 Label* map_check() { return &map_check_; }
2408
2409 private:
2410 LInstanceOfKnownGlobal* instr_;
2411 Label map_check_;
2412 };
2413
2414 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002415 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416
2417 Label done, false_result;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002418 Register object = ToRegister(instr->value());
2419 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002420 Register result = ToRegister(instr->result());
2421
2422 ASSERT(object.is(a0));
2423 ASSERT(result.is(v0));
2424
2425 // A Smi is not instance of anything.
2426 __ JumpIfSmi(object, &false_result);
2427
2428 // This is the inlined call site instanceof cache. The two occurences of the
2429 // hole value will be patched to the last map/result pair generated by the
2430 // instanceof stub.
2431 Label cache_miss;
2432 Register map = temp;
2433 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset));
2434
2435 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
2436 __ bind(deferred->map_check()); // Label for calculating code patching.
2437 // We use Factory::the_hole_value() on purpose instead of loading from the
2438 // root array to force relocation to be able to later patch with
2439 // the cached map.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002440 Handle<JSGlobalPropertyCell> cell =
2441 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value());
2442 __ li(at, Operand(Handle<Object>(cell)));
2443 __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002444 __ Branch(&cache_miss, ne, map, Operand(at));
2445 // We use Factory::the_hole_value() on purpose instead of loading from the
2446 // root array to force relocation to be able to later patch
2447 // with true or false.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002448 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002449 __ Branch(&done);
2450
2451 // The inlined call site cache did not match. Check null and string before
2452 // calling the deferred code.
2453 __ bind(&cache_miss);
2454 // Null is not instance of anything.
2455 __ LoadRoot(temp, Heap::kNullValueRootIndex);
2456 __ Branch(&false_result, eq, object, Operand(temp));
2457
2458 // String values is not instance of anything.
2459 Condition cc = __ IsObjectStringType(object, temp, temp);
2460 __ Branch(&false_result, cc, temp, Operand(zero_reg));
2461
2462 // Go to the deferred code.
2463 __ Branch(deferred->entry());
2464
2465 __ bind(&false_result);
2466 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2467
2468 // Here result has either true or false. Deferred code also produces true or
2469 // false object.
2470 __ bind(deferred->exit());
2471 __ bind(&done);
2472}
2473
2474
erikcorry0ad885c2011-11-21 13:51:57 +00002475void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2476 Label* map_check) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002477 Register result = ToRegister(instr->result());
2478 ASSERT(result.is(v0));
2479
2480 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2481 flags = static_cast<InstanceofStub::Flags>(
2482 flags | InstanceofStub::kArgsInRegisters);
2483 flags = static_cast<InstanceofStub::Flags>(
2484 flags | InstanceofStub::kCallSiteInlineCheck);
2485 flags = static_cast<InstanceofStub::Flags>(
2486 flags | InstanceofStub::kReturnTrueFalseObject);
2487 InstanceofStub stub(flags);
2488
2489 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
2490
2491 // Get the temp register reserved by the instruction. This needs to be t0 as
2492 // its slot of the pushing of safepoint registers is used to communicate the
2493 // offset to the location of the map check.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002494 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002495 ASSERT(temp.is(t0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002496 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002497 static const int kAdditionalDelta = 7;
2498 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2499 Label before_push_delta;
2500 __ bind(&before_push_delta);
2501 {
2502 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002503 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002504 __ StoreToSafepointRegisterSlot(temp, temp);
2505 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002506 CallCodeGeneric(stub.GetCode(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002507 RelocInfo::CODE_TARGET,
2508 instr,
2509 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00002510 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
erikcorry0ad885c2011-11-21 13:51:57 +00002511 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002512 // Put the result value into the result register slot and
2513 // restore all registers.
2514 __ StoreToSafepointRegisterSlot(result, result);
2515}
2516
2517
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002518void LCodeGen::DoInstanceSize(LInstanceSize* instr) {
2519 Register object = ToRegister(instr->object());
2520 Register result = ToRegister(instr->result());
2521 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
2522 __ lbu(result, FieldMemOperand(result, Map::kInstanceSizeOffset));
2523}
2524
2525
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002526void LCodeGen::DoCmpT(LCmpT* instr) {
2527 Token::Value op = instr->op();
2528
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002529 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002530 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2531 // On MIPS there is no need for a "no inlined smi code" marker (nop).
2532
2533 Condition condition = ComputeCompareCondition(op);
2534 // A minor optimization that relies on LoadRoot always emitting one
2535 // instruction.
2536 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002537 Label done, check;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002538 __ Branch(USE_DELAY_SLOT, &done, condition, v0, Operand(zero_reg));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002539 __ bind(&check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002540 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002541 ASSERT_EQ(1, masm()->InstructionsGeneratedSince(&check));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002542 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002543 __ bind(&done);
2544}
2545
2546
2547void LCodeGen::DoReturn(LReturn* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002548 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002549 // Push the return value on the stack as the parameter.
2550 // Runtime::TraceExit returns its parameter in v0.
2551 __ push(v0);
2552 __ CallRuntime(Runtime::kTraceExit, 1);
2553 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002554 if (info()->saves_caller_doubles()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002555 ASSERT(NeedsEagerFrame());
2556 BitVector* doubles = chunk()->allocated_double_registers();
2557 BitVector::Iterator save_iterator(doubles);
2558 int count = 0;
2559 while (!save_iterator.Done()) {
2560 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
2561 MemOperand(sp, count * kDoubleSize));
2562 save_iterator.Advance();
2563 count++;
2564 }
2565 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002566 int no_frame_start = -1;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002567 if (NeedsEagerFrame()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002568 __ mov(sp, fp);
2569 __ Pop(ra, fp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002570 no_frame_start = masm_->pc_offset();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002571 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002572 if (instr->has_constant_parameter_count()) {
2573 int parameter_count = ToInteger32(instr->constant_parameter_count());
2574 int32_t sp_delta = (parameter_count + 1) * kPointerSize;
2575 if (sp_delta != 0) {
2576 __ Addu(sp, sp, Operand(sp_delta));
2577 }
2578 } else {
2579 Register reg = ToRegister(instr->parameter_count());
2580 // The argument count parameter is a smi
2581 __ SmiUntag(reg);
2582 __ sll(at, reg, kPointerSizeLog2);
2583 __ Addu(sp, sp, at);
2584 }
2585
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002586 __ Jump(ra);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002587
2588 if (no_frame_start != -1) {
2589 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2590 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002591}
2592
2593
2594void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2595 Register result = ToRegister(instr->result());
2596 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell())));
2597 __ lw(result, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset));
2598 if (instr->hydrogen()->RequiresHoleCheck()) {
2599 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2600 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2601 }
2602}
2603
2604
2605void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2606 ASSERT(ToRegister(instr->global_object()).is(a0));
2607 ASSERT(ToRegister(instr->result()).is(v0));
2608
2609 __ li(a2, Operand(instr->name()));
2610 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET
2611 : RelocInfo::CODE_TARGET_CONTEXT;
2612 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2613 CallCode(ic, mode, instr);
2614}
2615
2616
2617void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002618 Register value = ToRegister(instr->value());
2619 Register cell = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002620
2621 // Load the cell.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002622 __ li(cell, Operand(instr->hydrogen()->cell()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002623
2624 // If the cell we are storing to contains the hole it could have
2625 // been deleted from the property dictionary. In that case, we need
2626 // to update the property details in the property dictionary to mark
2627 // it as no longer deleted.
2628 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002629 // We use a temp to check the payload.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002630 Register payload = ToRegister(instr->temp());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002631 __ lw(payload, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002632 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002633 DeoptimizeIf(eq, instr->environment(), payload, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002634 }
2635
2636 // Store the value.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002637 __ sw(value, FieldMemOperand(cell, JSGlobalPropertyCell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002638 // Cells are always rescanned, so no write barrier here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002639}
2640
2641
2642void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2643 ASSERT(ToRegister(instr->global_object()).is(a1));
2644 ASSERT(ToRegister(instr->value()).is(a0));
2645
2646 __ li(a2, Operand(instr->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002647 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002648 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2649 : isolate()->builtins()->StoreIC_Initialize();
2650 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2651}
2652
2653
2654void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2655 Register context = ToRegister(instr->context());
2656 Register result = ToRegister(instr->result());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002657
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002658 __ lw(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002659 if (instr->hydrogen()->RequiresHoleCheck()) {
2660 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002661
2662 if (instr->hydrogen()->DeoptimizesOnHole()) {
2663 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2664 } else {
2665 Label is_not_hole;
2666 __ Branch(&is_not_hole, ne, result, Operand(at));
2667 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2668 __ bind(&is_not_hole);
2669 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002670 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002671}
2672
2673
2674void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2675 Register context = ToRegister(instr->context());
2676 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002677 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002678 MemOperand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002679
2680 Label skip_assignment;
2681
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002682 if (instr->hydrogen()->RequiresHoleCheck()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002683 __ lw(scratch, target);
2684 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002685
2686 if (instr->hydrogen()->DeoptimizesOnHole()) {
2687 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
2688 } else {
2689 __ Branch(&skip_assignment, ne, scratch, Operand(at));
2690 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002691 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002692
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002693 __ sw(value, target);
2694 if (instr->hydrogen()->NeedsWriteBarrier()) {
2695 HType type = instr->hydrogen()->value()->type();
2696 SmiCheck check_needed =
2697 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
2698 __ RecordWriteContextSlot(context,
2699 target.offset(),
2700 value,
2701 scratch0(),
danno@chromium.orgc99cd482013-03-21 15:26:42 +00002702 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002703 kSaveFPRegs,
2704 EMIT_REMEMBERED_SET,
2705 check_needed);
2706 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002707
2708 __ bind(&skip_assignment);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002709}
2710
2711
2712void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002713 HObjectAccess access = instr->hydrogen()->access();
2714 int offset = access.offset();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002715 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002716 if (instr->hydrogen()->representation().IsDouble()) {
2717 DoubleRegister result = ToDoubleRegister(instr->result());
2718 __ ldc1(result, FieldMemOperand(object, offset));
2719 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002720 }
2721
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002722 Register result = ToRegister(instr->result());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002723 if (access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002724 __ lw(result, FieldMemOperand(object, offset));
2725 } else {
2726 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2727 __ lw(result, FieldMemOperand(result, offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002728 }
2729}
2730
2731
2732void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2733 Register object,
2734 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002735 Handle<String> name,
2736 LEnvironment* env) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002737 LookupResult lookup(isolate());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002738 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002739 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002740 if (lookup.IsField()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002741 int index = lookup.GetLocalFieldIndexFromMap(*type);
2742 int offset = index * kPointerSize;
2743 if (index < 0) {
2744 // Negative property indices are in-object properties, indexed
2745 // from the end of the fixed part of the object.
2746 __ lw(result, FieldMemOperand(object, offset + type->instance_size()));
2747 } else {
2748 // Non-negative property indices are in the properties array.
2749 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2750 __ lw(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
2751 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002752 } else if (lookup.IsConstantFunction()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002753 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002754 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002755 } else {
2756 // Negative lookup.
2757 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002758 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002759 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002760 while (*current != heap->null_value()) {
2761 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002762 __ lw(result, FieldMemOperand(result, HeapObject::kMapOffset));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002763 DeoptimizeIf(ne, env, result, Operand(Handle<Map>(current->map())));
2764 current =
2765 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002766 }
2767 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002768 }
2769}
2770
2771
2772void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2773 Register object = ToRegister(instr->object());
2774 Register result = ToRegister(instr->result());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002775 Register object_map = scratch0();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002776
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002777 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002778 bool need_generic = instr->hydrogen()->need_generic();
2779
2780 if (map_count == 0 && !need_generic) {
2781 DeoptimizeIf(al, instr->environment());
2782 return;
2783 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002784 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002785 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002786 __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002787 for (int i = 0; i < map_count; ++i) {
2788 bool last = (i == map_count - 1);
2789 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002790 Label check_passed;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002791 __ CompareMapAndBranch(object_map, map, &check_passed, eq, &check_passed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002792 if (last && !need_generic) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002793 DeoptimizeIf(al, instr->environment());
2794 __ bind(&check_passed);
2795 EmitLoadFieldOrConstantFunction(
2796 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002797 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002798 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002799 __ Branch(&next);
2800 __ bind(&check_passed);
2801 EmitLoadFieldOrConstantFunction(
2802 result, object, map, name, instr->environment());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002803 __ Branch(&done);
2804 __ bind(&next);
2805 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002806 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002807 if (need_generic) {
2808 __ li(a2, Operand(name));
2809 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2810 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2811 }
2812 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002813}
2814
2815
2816void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
2817 ASSERT(ToRegister(instr->object()).is(a0));
2818 ASSERT(ToRegister(instr->result()).is(v0));
2819
2820 // Name is always in a2.
2821 __ li(a2, Operand(instr->name()));
2822 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2823 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2824}
2825
2826
2827void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2828 Register scratch = scratch0();
2829 Register function = ToRegister(instr->function());
2830 Register result = ToRegister(instr->result());
2831
2832 // Check that the function really is a function. Load map into the
2833 // result register.
2834 __ GetObjectType(function, result, scratch);
2835 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_FUNCTION_TYPE));
2836
2837 // Make sure that the function has an instance prototype.
2838 Label non_instance;
2839 __ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
2840 __ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
2841 __ Branch(&non_instance, ne, scratch, Operand(zero_reg));
2842
2843 // Get the prototype or initial map from the function.
2844 __ lw(result,
2845 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2846
2847 // Check that the function has a prototype or an initial map.
2848 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2849 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2850
2851 // If the function does not have an initial map, we're done.
2852 Label done;
2853 __ GetObjectType(result, scratch, scratch);
2854 __ Branch(&done, ne, scratch, Operand(MAP_TYPE));
2855
2856 // Get the prototype from the initial map.
2857 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
2858 __ Branch(&done);
2859
2860 // Non-instance prototype: Fetch prototype from constructor field
2861 // in initial map.
2862 __ bind(&non_instance);
2863 __ lw(result, FieldMemOperand(result, Map::kConstructorOffset));
2864
2865 // All done.
2866 __ bind(&done);
2867}
2868
2869
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002870void LCodeGen::DoLoadExternalArrayPointer(
2871 LLoadExternalArrayPointer* instr) {
2872 Register to_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002873 Register from_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002874 __ lw(to_reg, FieldMemOperand(from_reg,
2875 ExternalArray::kExternalPointerOffset));
2876}
2877
2878
2879void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
2880 Register arguments = ToRegister(instr->arguments());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002881 Register result = ToRegister(instr->result());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002882 if (instr->length()->IsConstantOperand() &&
2883 instr->index()->IsConstantOperand()) {
2884 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2885 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
2886 int index = (const_length - const_index) + 1;
2887 __ lw(result, MemOperand(arguments, index * kPointerSize));
2888 } else {
2889 Register length = ToRegister(instr->length());
2890 Register index = ToRegister(instr->index());
2891 // There are two words between the frame pointer and the last argument.
2892 // Subtracting from length accounts for one of them, add one more.
2893 __ subu(length, length, index);
2894 __ Addu(length, length, Operand(1));
2895 __ sll(length, length, kPointerSizeLog2);
2896 __ Addu(at, arguments, Operand(length));
2897 __ lw(result, MemOperand(at, 0));
2898 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002899}
2900
2901
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002902void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
2903 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002904 Register key = no_reg;
2905 ElementsKind elements_kind = instr->elements_kind();
2906 bool key_is_constant = instr->key()->IsConstantOperand();
2907 int constant_key = 0;
2908 if (key_is_constant) {
2909 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
2910 if (constant_key & 0xF0000000) {
2911 Abort("array index constant value too big.");
2912 }
2913 } else {
2914 key = ToRegister(instr->key());
2915 }
danno@chromium.org129d3982012-07-25 15:01:47 +00002916 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002917 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00002918 ? (element_size_shift - kSmiTagSize) : element_size_shift;
2919 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002920
2921 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
2922 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
2923 FPURegister result = ToDoubleRegister(instr->result());
2924 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00002925 __ Addu(scratch0(), external_pointer, constant_key << element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002926 } else {
2927 __ sll(scratch0(), key, shift_size);
2928 __ Addu(scratch0(), scratch0(), external_pointer);
2929 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002930 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
2931 __ lwc1(result, MemOperand(scratch0(), additional_offset));
2932 __ cvt_d_s(result, result);
2933 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
2934 __ ldc1(result, MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002935 }
2936 } else {
2937 Register result = ToRegister(instr->result());
danno@chromium.org129d3982012-07-25 15:01:47 +00002938 MemOperand mem_operand = PrepareKeyedOperand(
2939 key, external_pointer, key_is_constant, constant_key,
2940 element_size_shift, shift_size,
2941 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002942 switch (elements_kind) {
2943 case EXTERNAL_BYTE_ELEMENTS:
2944 __ lb(result, mem_operand);
2945 break;
2946 case EXTERNAL_PIXEL_ELEMENTS:
2947 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2948 __ lbu(result, mem_operand);
2949 break;
2950 case EXTERNAL_SHORT_ELEMENTS:
2951 __ lh(result, mem_operand);
2952 break;
2953 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2954 __ lhu(result, mem_operand);
2955 break;
2956 case EXTERNAL_INT_ELEMENTS:
2957 __ lw(result, mem_operand);
2958 break;
2959 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2960 __ lw(result, mem_operand);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002961 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
2962 DeoptimizeIf(Ugreater_equal, instr->environment(),
2963 result, Operand(0x80000000));
2964 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002965 break;
2966 case EXTERNAL_FLOAT_ELEMENTS:
2967 case EXTERNAL_DOUBLE_ELEMENTS:
2968 case FAST_DOUBLE_ELEMENTS:
2969 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002970 case FAST_SMI_ELEMENTS:
2971 case FAST_HOLEY_DOUBLE_ELEMENTS:
2972 case FAST_HOLEY_ELEMENTS:
2973 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002974 case DICTIONARY_ELEMENTS:
2975 case NON_STRICT_ARGUMENTS_ELEMENTS:
2976 UNREACHABLE();
2977 break;
2978 }
2979 }
2980}
2981
2982
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002983void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
2984 Register elements = ToRegister(instr->elements());
2985 bool key_is_constant = instr->key()->IsConstantOperand();
2986 Register key = no_reg;
2987 DoubleRegister result = ToDoubleRegister(instr->result());
2988 Register scratch = scratch0();
2989
2990 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002991 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002992 ? (element_size_shift - kSmiTagSize) : element_size_shift;
2993 int constant_key = 0;
2994 if (key_is_constant) {
2995 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
2996 if (constant_key & 0xF0000000) {
2997 Abort("array index constant value too big.");
2998 }
2999 } else {
3000 key = ToRegister(instr->key());
3001 }
3002
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003003 int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
3004 ((constant_key + instr->additional_index()) << element_size_shift);
3005 if (!key_is_constant) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003006 __ sll(scratch, key, shift_size);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003007 __ Addu(elements, elements, scratch);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003008 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003009 __ Addu(elements, elements, Operand(base_offset));
3010 __ ldc1(result, MemOperand(elements));
3011 if (instr->hydrogen()->RequiresHoleCheck()) {
3012 __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
3013 DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003014 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003015}
3016
3017
3018void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3019 Register elements = ToRegister(instr->elements());
3020 Register result = ToRegister(instr->result());
3021 Register scratch = scratch0();
3022 Register store_base = scratch;
3023 int offset = 0;
3024
3025 if (instr->key()->IsConstantOperand()) {
3026 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3027 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
3028 instr->additional_index());
3029 store_base = elements;
3030 } else {
3031 Register key = EmitLoadRegister(instr->key(), scratch0());
3032 // Even though the HLoadKeyed instruction forces the input
3033 // representation for the key to be an integer, the input gets replaced
3034 // during bound check elimination with the index argument to the bounds
3035 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003036 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003037 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
3038 __ addu(scratch, elements, scratch);
3039 } else {
3040 __ sll(scratch, key, kPointerSizeLog2);
3041 __ addu(scratch, elements, scratch);
3042 }
3043 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
3044 }
3045 __ lw(result, FieldMemOperand(store_base, offset));
3046
3047 // Check for the hole value.
3048 if (instr->hydrogen()->RequiresHoleCheck()) {
3049 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3050 __ And(scratch, result, Operand(kSmiTagMask));
3051 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3052 } else {
3053 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3054 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch));
3055 }
3056 }
3057}
3058
3059
3060void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3061 if (instr->is_external()) {
3062 DoLoadKeyedExternalArray(instr);
3063 } else if (instr->hydrogen()->representation().IsDouble()) {
3064 DoLoadKeyedFixedDoubleArray(instr);
3065 } else {
3066 DoLoadKeyedFixedArray(instr);
3067 }
3068}
3069
3070
3071MemOperand LCodeGen::PrepareKeyedOperand(Register key,
3072 Register base,
3073 bool key_is_constant,
3074 int constant_key,
3075 int element_size,
3076 int shift_size,
3077 int additional_index,
3078 int additional_offset) {
3079 if (additional_index != 0 && !key_is_constant) {
3080 additional_index *= 1 << (element_size - shift_size);
3081 __ Addu(scratch0(), key, Operand(additional_index));
3082 }
3083
3084 if (key_is_constant) {
3085 return MemOperand(base,
3086 (constant_key << element_size) + additional_offset);
3087 }
3088
3089 if (additional_index == 0) {
3090 if (shift_size >= 0) {
3091 __ sll(scratch0(), key, shift_size);
3092 __ Addu(scratch0(), base, scratch0());
3093 return MemOperand(scratch0());
3094 } else {
3095 ASSERT_EQ(-1, shift_size);
3096 __ srl(scratch0(), key, 1);
3097 __ Addu(scratch0(), base, scratch0());
3098 return MemOperand(scratch0());
3099 }
3100 }
3101
3102 if (shift_size >= 0) {
3103 __ sll(scratch0(), scratch0(), shift_size);
3104 __ Addu(scratch0(), base, scratch0());
3105 return MemOperand(scratch0());
3106 } else {
3107 ASSERT_EQ(-1, shift_size);
3108 __ srl(scratch0(), scratch0(), 1);
3109 __ Addu(scratch0(), base, scratch0());
3110 return MemOperand(scratch0());
3111 }
3112}
3113
3114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003115void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3116 ASSERT(ToRegister(instr->object()).is(a1));
3117 ASSERT(ToRegister(instr->key()).is(a0));
3118
3119 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
3120 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3121}
3122
3123
3124void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3125 Register scratch = scratch0();
3126 Register temp = scratch1();
3127 Register result = ToRegister(instr->result());
3128
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003129 if (instr->hydrogen()->from_inlined()) {
3130 __ Subu(result, sp, 2 * kPointerSize);
3131 } else {
3132 // Check if the calling frame is an arguments adaptor frame.
3133 Label done, adapted;
3134 __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3135 __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
3136 __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003137
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003138 // Result is the frame pointer for the frame if not adapted and for the real
3139 // frame below the adaptor frame if adapted.
3140 __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
3141 __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
3142 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003143}
3144
3145
3146void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003147 Register elem = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003148 Register result = ToRegister(instr->result());
3149
3150 Label done;
3151
3152 // If no arguments adaptor frame the number of arguments is fixed.
3153 __ Addu(result, zero_reg, Operand(scope()->num_parameters()));
3154 __ Branch(&done, eq, fp, Operand(elem));
3155
3156 // Arguments adaptor frame present. Get argument length from there.
3157 __ lw(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3158 __ lw(result,
3159 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
3160 __ SmiUntag(result);
3161
3162 // Argument length is in result register.
3163 __ bind(&done);
3164}
3165
3166
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003167void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003168 Register receiver = ToRegister(instr->receiver());
3169 Register function = ToRegister(instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003170 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003171
3172 // If the receiver is null or undefined, we have to pass the global
3173 // object as a receiver to normal functions. Values have to be
3174 // passed unchanged to builtins and strict-mode functions.
3175 Label global_object, receiver_ok;
3176
3177 // Do not transform the receiver to object for strict mode
3178 // functions.
3179 __ lw(scratch,
3180 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
3181 __ lw(scratch,
3182 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
3183
3184 // Do not transform the receiver to object for builtins.
3185 int32_t strict_mode_function_mask =
3186 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
3187 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
3188 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask));
3189 __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg));
3190
3191 // Normal function. Replace undefined or null with global receiver.
3192 __ LoadRoot(scratch, Heap::kNullValueRootIndex);
3193 __ Branch(&global_object, eq, receiver, Operand(scratch));
3194 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
3195 __ Branch(&global_object, eq, receiver, Operand(scratch));
3196
3197 // Deoptimize if the receiver is not a JS object.
3198 __ And(scratch, receiver, Operand(kSmiTagMask));
3199 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3200
3201 __ GetObjectType(receiver, scratch, scratch);
3202 DeoptimizeIf(lt, instr->environment(),
3203 scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
3204 __ Branch(&receiver_ok);
3205
3206 __ bind(&global_object);
3207 __ lw(receiver, GlobalObjectOperand());
3208 __ lw(receiver,
3209 FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
3210 __ bind(&receiver_ok);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003211}
3212
3213void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3214 Register receiver = ToRegister(instr->receiver());
3215 Register function = ToRegister(instr->function());
3216 Register length = ToRegister(instr->length());
3217 Register elements = ToRegister(instr->elements());
3218 Register scratch = scratch0();
3219 ASSERT(receiver.is(a0)); // Used for parameter count.
3220 ASSERT(function.is(a1)); // Required by InvokeFunction.
3221 ASSERT(ToRegister(instr->result()).is(v0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003222
3223 // Copy the arguments to this function possibly from the
3224 // adaptor frame below it.
3225 const uint32_t kArgumentsLimit = 1 * KB;
3226 DeoptimizeIf(hi, instr->environment(), length, Operand(kArgumentsLimit));
3227
3228 // Push the receiver and use the register to keep the original
3229 // number of arguments.
3230 __ push(receiver);
3231 __ Move(receiver, length);
3232 // The arguments are at a one pointer size offset from elements.
3233 __ Addu(elements, elements, Operand(1 * kPointerSize));
3234
3235 // Loop through the arguments pushing them onto the execution
3236 // stack.
3237 Label invoke, loop;
3238 // length is a small non-negative integer, due to the test above.
3239 __ Branch(USE_DELAY_SLOT, &invoke, eq, length, Operand(zero_reg));
3240 __ sll(scratch, length, 2);
3241 __ bind(&loop);
3242 __ Addu(scratch, elements, scratch);
3243 __ lw(scratch, MemOperand(scratch));
3244 __ push(scratch);
3245 __ Subu(length, length, Operand(1));
3246 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg));
3247 __ sll(scratch, length, 2);
3248
3249 __ bind(&invoke);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00003250 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003251 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003252 RecordPosition(pointers->position());
erikcorry0ad885c2011-11-21 13:51:57 +00003253 SafepointGenerator safepoint_generator(
3254 this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003255 // The number of arguments is stored in receiver which is a0, as expected
3256 // by InvokeFunction.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003257 ParameterCount actual(receiver);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003258 __ InvokeFunction(function, actual, CALL_FUNCTION,
3259 safepoint_generator, CALL_AS_METHOD);
3260 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3261}
3262
3263
3264void LCodeGen::DoPushArgument(LPushArgument* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003265 LOperand* argument = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003266 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
3267 Abort("DoPushArgument not implemented for double type.");
3268 } else {
3269 Register argument_reg = EmitLoadRegister(argument, at);
3270 __ push(argument_reg);
3271 }
3272}
3273
3274
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003275void LCodeGen::DoDrop(LDrop* instr) {
3276 __ Drop(instr->count());
3277}
3278
3279
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003280void LCodeGen::DoThisFunction(LThisFunction* instr) {
3281 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003282 __ lw(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003283}
3284
3285
3286void LCodeGen::DoContext(LContext* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003287 // If there is a non-return use, the context must be moved to a register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003288 Register result = ToRegister(instr->result());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003289 for (HUseIterator it(instr->hydrogen()->uses()); !it.Done(); it.Advance()) {
3290 if (!it.value()->IsReturn()) {
3291 __ mov(result, cp);
3292 return;
3293 }
3294 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003295}
3296
3297
3298void LCodeGen::DoOuterContext(LOuterContext* instr) {
3299 Register context = ToRegister(instr->context());
3300 Register result = ToRegister(instr->result());
3301 __ lw(result,
3302 MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
3303}
3304
3305
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003306void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3307 __ LoadHeapObject(scratch0(), instr->hydrogen()->pairs());
3308 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags())));
3309 // The context is the first argument.
3310 __ Push(cp, scratch0(), scratch1());
3311 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3312}
3313
3314
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003315void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003316 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003317 __ lw(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003318}
3319
3320
3321void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003322 Register global = ToRegister(instr->global_object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003323 Register result = ToRegister(instr->result());
3324 __ lw(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
3325}
3326
3327
3328void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003329 int formal_parameter_count,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003330 int arity,
3331 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003332 CallKind call_kind,
3333 A1State a1_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003334 bool dont_adapt_arguments =
3335 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3336 bool can_invoke_directly =
3337 dont_adapt_arguments || formal_parameter_count == arity;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003338
3339 LPointerMap* pointers = instr->pointer_map();
3340 RecordPosition(pointers->position());
3341
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003342 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003343 if (a1_state == A1_UNINITIALIZED) {
3344 __ LoadHeapObject(a1, function);
3345 }
3346
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003347 // Change context.
3348 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003349
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003350 // Set r0 to arguments count if adaption is not needed. Assumes that r0
3351 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003352 if (dont_adapt_arguments) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003353 __ li(a0, Operand(arity));
3354 }
3355
3356 // Invoke function.
3357 __ SetCallKind(t1, call_kind);
3358 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
3359 __ Call(at);
3360
3361 // Set up deoptimization.
3362 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3363 } else {
3364 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3365 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003366 ParameterCount expected(formal_parameter_count);
3367 __ InvokeFunction(
3368 function, expected, count, CALL_FUNCTION, generator, call_kind);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003369 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003370
3371 // Restore context.
3372 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3373}
3374
3375
3376void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3377 ASSERT(ToRegister(instr->result()).is(v0));
3378 __ mov(a0, v0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003379 CallKnownFunction(instr->hydrogen()->function(),
3380 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003381 instr->arity(),
3382 instr,
3383 CALL_AS_METHOD,
3384 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003385}
3386
3387
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003388void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003389 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003390 Register result = ToRegister(instr->result());
3391 Register scratch = scratch0();
3392
3393 // Deoptimize if not a heap number.
3394 __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
3395 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3396 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
3397
3398 Label done;
3399 Register exponent = scratch0();
3400 scratch = no_reg;
3401 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3402 // Check the sign of the argument. If the argument is positive, just
3403 // return it.
3404 __ Move(result, input);
3405 __ And(at, exponent, Operand(HeapNumber::kSignMask));
3406 __ Branch(&done, eq, at, Operand(zero_reg));
3407
3408 // Input is negative. Reverse its sign.
3409 // Preserve the value of all registers.
3410 {
3411 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3412
3413 // Registers were saved at the safepoint, so we can use
3414 // many scratch registers.
3415 Register tmp1 = input.is(a1) ? a0 : a1;
3416 Register tmp2 = input.is(a2) ? a0 : a2;
3417 Register tmp3 = input.is(a3) ? a0 : a3;
3418 Register tmp4 = input.is(t0) ? a0 : t0;
3419
3420 // exponent: floating point exponent value.
3421
3422 Label allocated, slow;
3423 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
3424 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
3425 __ Branch(&allocated);
3426
3427 // Slow case: Call the runtime system to do the number allocation.
3428 __ bind(&slow);
3429
3430 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
3431 // Set the pointer to the new heap number in tmp.
3432 if (!tmp1.is(v0))
3433 __ mov(tmp1, v0);
3434 // Restore input_reg after call to runtime.
3435 __ LoadFromSafepointRegisterSlot(input, input);
3436 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3437
3438 __ bind(&allocated);
3439 // exponent: floating point exponent value.
3440 // tmp1: allocated heap number.
3441 __ And(exponent, exponent, Operand(~HeapNumber::kSignMask));
3442 __ sw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
3443 __ lw(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
3444 __ sw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
3445
3446 __ StoreToSafepointRegisterSlot(tmp1, result);
3447 }
3448
3449 __ bind(&done);
3450}
3451
3452
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003453void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003454 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003455 Register result = ToRegister(instr->result());
3456 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
3457 Label done;
3458 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg));
3459 __ mov(result, input);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003460 // Overflow if result is still negative, i.e. 0x80000000.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003461 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
3462 __ bind(&done);
3463}
3464
3465
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003466void LCodeGen::DoMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003467 // Class for deferred case.
3468 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3469 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003470 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003471 : LDeferredCode(codegen), instr_(instr) { }
3472 virtual void Generate() {
3473 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3474 }
3475 virtual LInstruction* instr() { return instr_; }
3476 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003477 LMathAbs* instr_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003478 };
3479
3480 Representation r = instr->hydrogen()->value()->representation();
3481 if (r.IsDouble()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003482 FPURegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003483 FPURegister result = ToDoubleRegister(instr->result());
3484 __ abs_d(result, input);
3485 } else if (r.IsInteger32()) {
3486 EmitIntegerMathAbs(instr);
3487 } else {
3488 // Representation is tagged.
3489 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003490 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003491 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003492 // Smi check.
3493 __ JumpIfNotSmi(input, deferred->entry());
3494 // If smi, handle it directly.
3495 EmitIntegerMathAbs(instr);
3496 __ bind(deferred->exit());
3497 }
3498}
3499
3500
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003501void LCodeGen::DoMathFloor(LMathFloor* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003502 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003503 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003504 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003505 Register except_flag = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003506
3507 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003508 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003509 input,
3510 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003511 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003512 except_flag);
3513
3514 // Deopt if the operation did not succeed.
3515 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3516
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003517 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3518 // Test for -0.
3519 Label done;
3520 __ Branch(&done, ne, result, Operand(zero_reg));
3521 __ mfc1(scratch1, input.high());
3522 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
3523 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
3524 __ bind(&done);
3525 }
3526}
3527
3528
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003529void LCodeGen::DoMathRound(LMathRound* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003530 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003531 Register result = ToRegister(instr->result());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003532 DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003533 Register scratch = scratch0();
3534 Label done, check_sign_on_zero;
3535
3536 // Extract exponent bits.
3537 __ mfc1(result, input.high());
3538 __ Ext(scratch,
3539 result,
3540 HeapNumber::kExponentShift,
3541 HeapNumber::kExponentBits);
3542
3543 // If the number is in ]-0.5, +0.5[, the result is +/- 0.
3544 Label skip1;
3545 __ Branch(&skip1, gt, scratch, Operand(HeapNumber::kExponentBias - 2));
3546 __ mov(result, zero_reg);
3547 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3548 __ Branch(&check_sign_on_zero);
3549 } else {
3550 __ Branch(&done);
3551 }
3552 __ bind(&skip1);
3553
3554 // The following conversion will not work with numbers
3555 // outside of ]-2^32, 2^32[.
3556 DeoptimizeIf(ge, instr->environment(), scratch,
3557 Operand(HeapNumber::kExponentBias + 32));
3558
3559 // Save the original sign for later comparison.
3560 __ And(scratch, result, Operand(HeapNumber::kSignMask));
3561
3562 __ Move(double_scratch0(), 0.5);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003563 __ add_d(double_scratch0(), input, double_scratch0());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003564
3565 // Check sign of the result: if the sign changed, the input
3566 // value was in ]0.5, 0[ and the result should be -0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003567 __ mfc1(result, double_scratch0().high());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003568 __ Xor(result, result, Operand(scratch));
3569 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3570 // ARM uses 'mi' here, which is 'lt'
3571 DeoptimizeIf(lt, instr->environment(), result,
3572 Operand(zero_reg));
3573 } else {
3574 Label skip2;
3575 // ARM uses 'mi' here, which is 'lt'
3576 // Negating it results in 'ge'
3577 __ Branch(&skip2, ge, result, Operand(zero_reg));
3578 __ mov(result, zero_reg);
3579 __ Branch(&done);
3580 __ bind(&skip2);
3581 }
3582
3583 Register except_flag = scratch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003584 __ EmitFPUTruncate(kRoundToMinusInf,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003585 result,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003586 double_scratch0(),
3587 at,
3588 double_scratch1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003589 except_flag);
3590
3591 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3592
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003593 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3594 // Test for -0.
3595 __ Branch(&done, ne, result, Operand(zero_reg));
3596 __ bind(&check_sign_on_zero);
3597 __ mfc1(scratch, input.high());
3598 __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
3599 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3600 }
3601 __ bind(&done);
3602}
3603
3604
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003605void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003606 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003607 DoubleRegister result = ToDoubleRegister(instr->result());
3608 __ sqrt_d(result, input);
3609}
3610
3611
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003612void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003613 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003614 DoubleRegister result = ToDoubleRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003615 DoubleRegister temp = ToDoubleRegister(instr->temp());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003616
3617 ASSERT(!input.is(result));
3618
3619 // Note that according to ECMA-262 15.8.2.13:
3620 // Math.pow(-Infinity, 0.5) == Infinity
3621 // Math.sqrt(-Infinity) == NaN
3622 Label done;
3623 __ Move(temp, -V8_INFINITY);
3624 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
3625 // Set up Infinity in the delay slot.
3626 // result is overwritten if the branch is not taken.
3627 __ neg_d(result, temp);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003628
3629 // Add +0 to convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003630 __ add_d(result, input, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003631 __ sqrt_d(result, result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003632 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003633}
3634
3635
3636void LCodeGen::DoPower(LPower* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003637 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003638 // Having marked this as a call, we can use any registers.
3639 // Just make sure that the input/output registers are the expected ones.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003640 ASSERT(!instr->right()->IsDoubleRegister() ||
3641 ToDoubleRegister(instr->right()).is(f4));
3642 ASSERT(!instr->right()->IsRegister() ||
3643 ToRegister(instr->right()).is(a2));
3644 ASSERT(ToDoubleRegister(instr->left()).is(f2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003645 ASSERT(ToDoubleRegister(instr->result()).is(f0));
3646
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003647 if (exponent_type.IsSmi()) {
3648 MathPowStub stub(MathPowStub::TAGGED);
3649 __ CallStub(&stub);
3650 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003651 Label no_deopt;
3652 __ JumpIfSmi(a2, &no_deopt);
3653 __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset));
3654 DeoptimizeIf(ne, instr->environment(), t3, Operand(at));
3655 __ bind(&no_deopt);
3656 MathPowStub stub(MathPowStub::TAGGED);
3657 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003658 } else if (exponent_type.IsInteger32()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003659 MathPowStub stub(MathPowStub::INTEGER);
3660 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003661 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003662 ASSERT(exponent_type.IsDouble());
3663 MathPowStub stub(MathPowStub::DOUBLE);
3664 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003665 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003666}
3667
3668
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003669void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003670 class DeferredDoRandom: public LDeferredCode {
3671 public:
3672 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3673 : LDeferredCode(codegen), instr_(instr) { }
3674 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3675 virtual LInstruction* instr() { return instr_; }
3676 private:
3677 LRandom* instr_;
3678 };
3679
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003680 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003681 // Having marked this instruction as a call we can use any
3682 // registers.
3683 ASSERT(ToDoubleRegister(instr->result()).is(f0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003684 ASSERT(ToRegister(instr->global_object()).is(a0));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003685
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003686 static const int kSeedSize = sizeof(uint32_t);
3687 STATIC_ASSERT(kPointerSize == kSeedSize);
3688
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003689 __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003690 static const int kRandomSeedOffset =
3691 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3692 __ lw(a2, FieldMemOperand(a0, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003693 // a2: FixedArray of the native context's random seeds
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003694
3695 // Load state[0].
3696 __ lw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
3697 __ Branch(deferred->entry(), eq, a1, Operand(zero_reg));
3698 // Load state[1].
3699 __ lw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
3700 // a1: state[0].
3701 // a0: state[1].
3702
3703 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3704 __ And(a3, a1, Operand(0xFFFF));
3705 __ li(t0, Operand(18273));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003706 __ Mul(a3, a3, t0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003707 __ srl(a1, a1, 16);
3708 __ Addu(a1, a3, a1);
3709 // Save state[0].
3710 __ sw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
3711
3712 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3713 __ And(a3, a0, Operand(0xFFFF));
3714 __ li(t0, Operand(36969));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003715 __ Mul(a3, a3, t0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003716 __ srl(a0, a0, 16),
3717 __ Addu(a0, a3, a0);
3718 // Save state[1].
3719 __ sw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
3720
3721 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3722 __ And(a0, a0, Operand(0x3FFFF));
3723 __ sll(a1, a1, 14);
3724 __ Addu(v0, a0, a1);
3725
3726 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003727
3728 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
3729 __ li(a2, Operand(0x41300000));
3730 // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
3731 __ Move(f12, v0, a2);
3732 // Move 0x4130000000000000 to FPU.
3733 __ Move(f14, zero_reg, a2);
3734 // Subtract to get the result.
3735 __ sub_d(f0, f12, f14);
3736}
3737
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003738void LCodeGen::DoDeferredRandom(LRandom* instr) {
3739 __ PrepareCallCFunction(1, scratch0());
3740 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3741 // Return value is in v0.
3742}
3743
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003744
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003745void LCodeGen::DoMathExp(LMathExp* instr) {
3746 DoubleRegister input = ToDoubleRegister(instr->value());
3747 DoubleRegister result = ToDoubleRegister(instr->result());
3748 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
3749 DoubleRegister double_scratch2 = double_scratch0();
3750 Register temp1 = ToRegister(instr->temp1());
3751 Register temp2 = ToRegister(instr->temp2());
3752
3753 MathExpGenerator::EmitMathExp(
3754 masm(), input, result, double_scratch1, double_scratch2,
3755 temp1, temp2, scratch0());
3756}
3757
3758
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003759void LCodeGen::DoMathLog(LMathLog* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003760 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3761 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3762 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003763 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003764}
3765
3766
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003767void LCodeGen::DoMathTan(LMathTan* instr) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00003768 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3769 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3770 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003771 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00003772}
3773
3774
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003775void LCodeGen::DoMathCos(LMathCos* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003776 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3777 TranscendentalCacheStub stub(TranscendentalCache::COS,
3778 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003779 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003780}
3781
3782
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003783void LCodeGen::DoMathSin(LMathSin* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003784 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3785 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3786 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003787 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003788}
3789
3790
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003791void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3792 ASSERT(ToRegister(instr->function()).is(a1));
3793 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003794
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003795 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3796 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003797 LPointerMap* pointers = instr->pointer_map();
3798 RecordPosition(pointers->position());
3799 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3800 ParameterCount count(instr->arity());
3801 __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3802 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3803 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003804 CallKnownFunction(known_function,
3805 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003806 instr->arity(),
3807 instr,
3808 CALL_AS_METHOD,
3809 A1_CONTAINS_TARGET);
3810 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003811}
3812
3813
3814void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
3815 ASSERT(ToRegister(instr->result()).is(v0));
3816
3817 int arity = instr->arity();
3818 Handle<Code> ic =
3819 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
3820 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3821 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3822}
3823
3824
3825void LCodeGen::DoCallNamed(LCallNamed* instr) {
3826 ASSERT(ToRegister(instr->result()).is(v0));
3827
3828 int arity = instr->arity();
3829 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3830 Handle<Code> ic =
3831 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
3832 __ li(a2, Operand(instr->name()));
3833 CallCode(ic, mode, instr);
3834 // Restore context register.
3835 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3836}
3837
3838
3839void LCodeGen::DoCallFunction(LCallFunction* instr) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003840 ASSERT(ToRegister(instr->function()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003841 ASSERT(ToRegister(instr->result()).is(v0));
3842
3843 int arity = instr->arity();
3844 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003845 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003846 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3847}
3848
3849
3850void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
3851 ASSERT(ToRegister(instr->result()).is(v0));
3852
3853 int arity = instr->arity();
3854 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
3855 Handle<Code> ic =
3856 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
3857 __ li(a2, Operand(instr->name()));
3858 CallCode(ic, mode, instr);
3859 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3860}
3861
3862
3863void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3864 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003865 CallKnownFunction(instr->hydrogen()->target(),
3866 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003867 instr->arity(),
3868 instr,
3869 CALL_AS_FUNCTION,
3870 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003871}
3872
3873
3874void LCodeGen::DoCallNew(LCallNew* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003875 ASSERT(ToRegister(instr->constructor()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003876 ASSERT(ToRegister(instr->result()).is(v0));
3877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003878 __ li(a0, Operand(instr->arity()));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003879 if (FLAG_optimize_constructed_arrays) {
3880 // No cell in a2 for construct type feedback in optimized code
3881 Handle<Object> undefined_value(isolate()->heap()->undefined_value(),
3882 isolate());
3883 __ li(a2, Operand(undefined_value));
3884 }
3885 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003886 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003887}
3888
3889
ulan@chromium.org750145a2013-03-07 15:14:13 +00003890void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
3891 ASSERT(ToRegister(instr->constructor()).is(a1));
3892 ASSERT(ToRegister(instr->result()).is(v0));
3893 ASSERT(FLAG_optimize_constructed_arrays);
3894
3895 __ li(a0, Operand(instr->arity()));
3896 __ li(a2, Operand(instr->hydrogen()->property_cell()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003897 ElementsKind kind = instr->hydrogen()->elements_kind();
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003898 if (instr->arity() == 0) {
3899 ArrayNoArgumentConstructorStub stub(kind);
3900 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3901 } else if (instr->arity() == 1) {
3902 ArraySingleArgumentConstructorStub stub(kind);
3903 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3904 } else {
3905 ArrayNArgumentsConstructorStub stub(kind);
3906 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
3907 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00003908}
3909
3910
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003911void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
3912 CallRuntime(instr->function(), instr->arity(), instr);
3913}
3914
3915
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00003916void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
3917 Register result = ToRegister(instr->result());
3918 Register base = ToRegister(instr->base_object());
3919 __ Addu(result, base, Operand(instr->offset()));
3920}
3921
3922
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003923void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003924 Representation representation = instr->representation();
3925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003926 Register object = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003927 Register scratch = scratch0();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003928 HObjectAccess access = instr->hydrogen()->access();
3929 int offset = access.offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003930
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003931 Handle<Map> transition = instr->transition();
3932
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003933 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003934 Register value = ToRegister(instr->value());
3935 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
3936 __ And(scratch, value, Operand(kSmiTagMask));
3937 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3938 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003939 } else if (FLAG_track_double_fields && representation.IsDouble()) {
3940 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003941 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003942 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3943 DoubleRegister value = ToDoubleRegister(instr->value());
3944 __ sdc1(value, FieldMemOperand(object, offset));
3945 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003946 }
3947
danno@chromium.orgf005df62013-04-30 16:36:45 +00003948 if (!transition.is_null()) {
3949 if (transition->CanBeDeprecated()) {
3950 transition_maps_.Add(transition, info()->zone());
3951 }
3952 __ li(scratch, Operand(transition));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003953 __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +00003954 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003955 Register temp = ToRegister(instr->temp());
verwaest@chromium.org37141392012-05-31 13:27:02 +00003956 // Update the write barrier for the map field.
3957 __ RecordWriteField(object,
3958 HeapObject::kMapOffset,
3959 scratch,
3960 temp,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003961 GetRAState(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00003962 kSaveFPRegs,
3963 OMIT_REMEMBERED_SET,
3964 OMIT_SMI_CHECK);
3965 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003966 }
3967
3968 // Do the store.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003969 Register value = ToRegister(instr->value());
3970 ASSERT(!object.is(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003971 HType type = instr->hydrogen()->value()->type();
3972 SmiCheck check_needed =
3973 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003974 if (access.IsInobject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003975 __ sw(value, FieldMemOperand(object, offset));
3976 if (instr->hydrogen()->NeedsWriteBarrier()) {
3977 // Update the write barrier for the object for in-object properties.
3978 __ RecordWriteField(object,
3979 offset,
3980 value,
3981 scratch,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003982 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003983 kSaveFPRegs,
3984 EMIT_REMEMBERED_SET,
3985 check_needed);
3986 }
3987 } else {
3988 __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
3989 __ sw(value, FieldMemOperand(scratch, offset));
3990 if (instr->hydrogen()->NeedsWriteBarrier()) {
3991 // Update the write barrier for the properties array.
3992 // object is used as a scratch register.
3993 __ RecordWriteField(scratch,
3994 offset,
3995 value,
3996 object,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00003997 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003998 kSaveFPRegs,
3999 EMIT_REMEMBERED_SET,
4000 check_needed);
4001 }
4002 }
4003}
4004
4005
4006void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
4007 ASSERT(ToRegister(instr->object()).is(a1));
4008 ASSERT(ToRegister(instr->value()).is(a0));
4009
4010 // Name is always in a2.
4011 __ li(a2, Operand(instr->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004012 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004013 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4014 : isolate()->builtins()->StoreIC_Initialize();
4015 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4016}
4017
4018
4019void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004020 if (instr->hydrogen()->skip_check()) return;
4021
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004022 if (instr->index()->IsConstantOperand()) {
4023 int constant_index =
4024 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004025 if (instr->hydrogen()->length()->representation().IsSmi()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004026 __ li(at, Operand(Smi::FromInt(constant_index)));
4027 } else {
4028 __ li(at, Operand(constant_index));
4029 }
4030 DeoptimizeIf(hs,
4031 instr->environment(),
4032 at,
4033 Operand(ToRegister(instr->length())));
4034 } else {
4035 DeoptimizeIf(hs,
4036 instr->environment(),
4037 ToRegister(instr->index()),
4038 Operand(ToRegister(instr->length())));
4039 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004040}
4041
4042
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004043void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4044 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004045 Register key = no_reg;
4046 ElementsKind elements_kind = instr->elements_kind();
4047 bool key_is_constant = instr->key()->IsConstantOperand();
4048 int constant_key = 0;
4049 if (key_is_constant) {
4050 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4051 if (constant_key & 0xF0000000) {
4052 Abort("array index constant value too big.");
4053 }
4054 } else {
4055 key = ToRegister(instr->key());
4056 }
danno@chromium.org129d3982012-07-25 15:01:47 +00004057 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004058 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00004059 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4060 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004061
4062 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
4063 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
4064 FPURegister value(ToDoubleRegister(instr->value()));
4065 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00004066 __ Addu(scratch0(), external_pointer, constant_key <<
4067 element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004068 } else {
4069 __ sll(scratch0(), key, shift_size);
4070 __ Addu(scratch0(), scratch0(), external_pointer);
4071 }
4072
4073 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4074 __ cvt_s_d(double_scratch0(), value);
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00004075 __ swc1(double_scratch0(), MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004076 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00004077 __ sdc1(value, MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004078 }
4079 } else {
4080 Register value(ToRegister(instr->value()));
danno@chromium.org129d3982012-07-25 15:01:47 +00004081 MemOperand mem_operand = PrepareKeyedOperand(
4082 key, external_pointer, key_is_constant, constant_key,
4083 element_size_shift, shift_size,
4084 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004085 switch (elements_kind) {
4086 case EXTERNAL_PIXEL_ELEMENTS:
4087 case EXTERNAL_BYTE_ELEMENTS:
4088 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4089 __ sb(value, mem_operand);
4090 break;
4091 case EXTERNAL_SHORT_ELEMENTS:
4092 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4093 __ sh(value, mem_operand);
4094 break;
4095 case EXTERNAL_INT_ELEMENTS:
4096 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4097 __ sw(value, mem_operand);
4098 break;
4099 case EXTERNAL_FLOAT_ELEMENTS:
4100 case EXTERNAL_DOUBLE_ELEMENTS:
4101 case FAST_DOUBLE_ELEMENTS:
4102 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004103 case FAST_SMI_ELEMENTS:
4104 case FAST_HOLEY_DOUBLE_ELEMENTS:
4105 case FAST_HOLEY_ELEMENTS:
4106 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004107 case DICTIONARY_ELEMENTS:
4108 case NON_STRICT_ARGUMENTS_ELEMENTS:
4109 UNREACHABLE();
4110 break;
4111 }
4112 }
4113}
4114
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004115
4116void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4117 DoubleRegister value = ToDoubleRegister(instr->value());
4118 Register elements = ToRegister(instr->elements());
4119 Register key = no_reg;
4120 Register scratch = scratch0();
4121 bool key_is_constant = instr->key()->IsConstantOperand();
4122 int constant_key = 0;
4123 Label not_nan;
4124
4125 // Calculate the effective address of the slot in the array to store the
4126 // double value.
4127 if (key_is_constant) {
4128 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4129 if (constant_key & 0xF0000000) {
4130 Abort("array index constant value too big.");
4131 }
4132 } else {
4133 key = ToRegister(instr->key());
4134 }
4135 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004136 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004137 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4138 if (key_is_constant) {
4139 __ Addu(scratch, elements, Operand((constant_key << element_size_shift) +
4140 FixedDoubleArray::kHeaderSize - kHeapObjectTag));
4141 } else {
4142 __ sll(scratch, key, shift_size);
4143 __ Addu(scratch, elements, Operand(scratch));
4144 __ Addu(scratch, scratch,
4145 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
4146 }
4147
4148 if (instr->NeedsCanonicalization()) {
4149 Label is_nan;
4150 // Check for NaN. All NaNs must be canonicalized.
4151 __ BranchF(NULL, &is_nan, eq, value, value);
4152 __ Branch(&not_nan);
4153
4154 // Only load canonical NaN if the comparison above set the overflow.
4155 __ bind(&is_nan);
4156 __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double());
4157 }
4158
4159 __ bind(&not_nan);
4160 __ sdc1(value, MemOperand(scratch, instr->additional_index() <<
4161 element_size_shift));
4162}
4163
4164
4165void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4166 Register value = ToRegister(instr->value());
4167 Register elements = ToRegister(instr->elements());
4168 Register key = instr->key()->IsRegister() ? ToRegister(instr->key())
4169 : no_reg;
4170 Register scratch = scratch0();
4171 Register store_base = scratch;
4172 int offset = 0;
4173
4174 // Do the store.
4175 if (instr->key()->IsConstantOperand()) {
4176 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4177 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
4178 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
4179 instr->additional_index());
4180 store_base = elements;
4181 } else {
4182 // Even though the HLoadKeyed instruction forces the input
4183 // representation for the key to be an integer, the input gets replaced
4184 // during bound check elimination with the index argument to the bounds
4185 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004186 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004187 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
4188 __ addu(scratch, elements, scratch);
4189 } else {
4190 __ sll(scratch, key, kPointerSizeLog2);
4191 __ addu(scratch, elements, scratch);
4192 }
4193 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
4194 }
4195 __ sw(value, FieldMemOperand(store_base, offset));
4196
4197 if (instr->hydrogen()->NeedsWriteBarrier()) {
4198 HType type = instr->hydrogen()->value()->type();
4199 SmiCheck check_needed =
4200 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
4201 // Compute address of modified element and store it into key register.
4202 __ Addu(key, store_base, Operand(offset - kHeapObjectTag));
4203 __ RecordWrite(elements,
4204 key,
4205 value,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004206 GetRAState(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004207 kSaveFPRegs,
4208 EMIT_REMEMBERED_SET,
4209 check_needed);
4210 }
4211}
4212
4213
4214void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4215 // By cases: external, fast double
4216 if (instr->is_external()) {
4217 DoStoreKeyedExternalArray(instr);
4218 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4219 DoStoreKeyedFixedDoubleArray(instr);
4220 } else {
4221 DoStoreKeyedFixedArray(instr);
4222 }
4223}
4224
4225
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004226void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
4227 ASSERT(ToRegister(instr->object()).is(a2));
4228 ASSERT(ToRegister(instr->key()).is(a1));
4229 ASSERT(ToRegister(instr->value()).is(a0));
4230
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004231 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004232 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4233 : isolate()->builtins()->KeyedStoreIC_Initialize();
4234 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4235}
4236
4237
4238void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4239 Register object_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004240 Register scratch = scratch0();
4241
4242 Handle<Map> from_map = instr->original_map();
4243 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004244 ElementsKind from_kind = instr->from_kind();
4245 ElementsKind to_kind = instr->to_kind();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004246
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004247 Label not_applicable;
4248 __ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4249 __ Branch(&not_applicable, ne, scratch, Operand(from_map));
4250
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004251 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004252 Register new_map_reg = ToRegister(instr->new_map_temp());
4253 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004254 __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4255 // Write barrier.
4256 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004257 scratch, GetRAState(), kDontSaveFPRegs);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004258 } else if (FLAG_compiled_transitions) {
4259 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4260 __ mov(a0, object_reg);
4261 __ li(a1, Operand(to_map));
4262 TransitionElementsKindStub stub(from_kind, to_kind);
4263 __ CallStub(&stub);
4264 RecordSafepointWithRegisters(
4265 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004266 } else if (IsFastSmiElementsKind(from_kind) &&
4267 IsFastDoubleElementsKind(to_kind)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004268 Register fixed_object_reg = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004269 ASSERT(fixed_object_reg.is(a2));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004270 Register new_map_reg = ToRegister(instr->new_map_temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004271 ASSERT(new_map_reg.is(a3));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004272 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 __ mov(fixed_object_reg, object_reg);
4274 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4275 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004276 } else if (IsFastDoubleElementsKind(from_kind) &&
4277 IsFastObjectElementsKind(to_kind)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004278 Register fixed_object_reg = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004279 ASSERT(fixed_object_reg.is(a2));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004280 Register new_map_reg = ToRegister(instr->new_map_temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004281 ASSERT(new_map_reg.is(a3));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004282 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004283 __ mov(fixed_object_reg, object_reg);
4284 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4285 RelocInfo::CODE_TARGET, instr);
4286 } else {
4287 UNREACHABLE();
4288 }
4289 __ bind(&not_applicable);
4290}
4291
4292
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004293void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4294 Register object = ToRegister(instr->object());
4295 Register temp = ToRegister(instr->temp());
4296 Label fail;
4297 __ TestJSArrayForAllocationSiteInfo(object, temp, ne, &fail);
4298 DeoptimizeIf(al, instr->environment());
4299 __ bind(&fail);
4300}
4301
4302
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004303void LCodeGen::DoStringAdd(LStringAdd* instr) {
4304 __ push(ToRegister(instr->left()));
4305 __ push(ToRegister(instr->right()));
4306 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004307 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004308}
4309
4310
4311void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4312 class DeferredStringCharCodeAt: public LDeferredCode {
4313 public:
4314 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4315 : LDeferredCode(codegen), instr_(instr) { }
4316 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
4317 virtual LInstruction* instr() { return instr_; }
4318 private:
4319 LStringCharCodeAt* instr_;
4320 };
4321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004322 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004323 new(zone()) DeferredStringCharCodeAt(this, instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004324 StringCharLoadGenerator::Generate(masm(),
4325 ToRegister(instr->string()),
4326 ToRegister(instr->index()),
4327 ToRegister(instr->result()),
4328 deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004329 __ bind(deferred->exit());
4330}
4331
4332
4333void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4334 Register string = ToRegister(instr->string());
4335 Register result = ToRegister(instr->result());
4336 Register scratch = scratch0();
4337
4338 // TODO(3095996): Get rid of this. For now, we need to make the
4339 // result register contain a valid pointer because it is already
4340 // contained in the register pointer map.
4341 __ mov(result, zero_reg);
4342
4343 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4344 __ push(string);
4345 // Push the index as a smi. This is safe because of the checks in
4346 // DoStringCharCodeAt above.
4347 if (instr->index()->IsConstantOperand()) {
4348 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4349 __ Addu(scratch, zero_reg, Operand(Smi::FromInt(const_index)));
4350 __ push(scratch);
4351 } else {
4352 Register index = ToRegister(instr->index());
4353 __ SmiTag(index);
4354 __ push(index);
4355 }
4356 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004357 __ AssertSmi(v0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004358 __ SmiUntag(v0);
4359 __ StoreToSafepointRegisterSlot(v0, result);
4360}
4361
4362
4363void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4364 class DeferredStringCharFromCode: public LDeferredCode {
4365 public:
4366 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4367 : LDeferredCode(codegen), instr_(instr) { }
4368 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
4369 virtual LInstruction* instr() { return instr_; }
4370 private:
4371 LStringCharFromCode* instr_;
4372 };
4373
4374 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004375 new(zone()) DeferredStringCharFromCode(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004376
4377 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4378 Register char_code = ToRegister(instr->char_code());
4379 Register result = ToRegister(instr->result());
4380 Register scratch = scratch0();
4381 ASSERT(!char_code.is(result));
4382
4383 __ Branch(deferred->entry(), hi,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004384 char_code, Operand(String::kMaxOneByteCharCode));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004385 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4386 __ sll(scratch, char_code, kPointerSizeLog2);
4387 __ Addu(result, result, scratch);
4388 __ lw(result, FieldMemOperand(result, FixedArray::kHeaderSize));
4389 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
4390 __ Branch(deferred->entry(), eq, result, Operand(scratch));
4391 __ bind(deferred->exit());
4392}
4393
4394
4395void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4396 Register char_code = ToRegister(instr->char_code());
4397 Register result = ToRegister(instr->result());
4398
4399 // TODO(3095996): Get rid of this. For now, we need to make the
4400 // result register contain a valid pointer because it is already
4401 // contained in the register pointer map.
4402 __ mov(result, zero_reg);
4403
4404 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4405 __ SmiTag(char_code);
4406 __ push(char_code);
4407 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
4408 __ StoreToSafepointRegisterSlot(v0, result);
4409}
4410
4411
4412void LCodeGen::DoStringLength(LStringLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004413 Register string = ToRegister(instr->string());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004414 Register result = ToRegister(instr->result());
4415 __ lw(result, FieldMemOperand(string, String::kLengthOffset));
4416}
4417
4418
4419void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004420 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004421 ASSERT(input->IsRegister() || input->IsStackSlot());
4422 LOperand* output = instr->result();
4423 ASSERT(output->IsDoubleRegister());
4424 FPURegister single_scratch = double_scratch0().low();
4425 if (input->IsStackSlot()) {
4426 Register scratch = scratch0();
4427 __ lw(scratch, ToMemOperand(input));
4428 __ mtc1(scratch, single_scratch);
4429 } else {
4430 __ mtc1(ToRegister(input), single_scratch);
4431 }
4432 __ cvt_d_w(ToDoubleRegister(output), single_scratch);
4433}
4434
4435
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004436void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4437 LOperand* input = instr->value();
4438 ASSERT(input->IsRegister());
4439 LOperand* output = instr->result();
4440 ASSERT(output->IsRegister());
4441 Register scratch = scratch0();
4442
4443 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch);
4444 if (!instr->hydrogen()->value()->HasRange() ||
4445 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4446 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
4447 }
4448}
4449
4450
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004451void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004452 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004453 LOperand* output = instr->result();
4454
4455 FPURegister dbl_scratch = double_scratch0();
4456 __ mtc1(ToRegister(input), dbl_scratch);
4457 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22);
4458}
4459
4460
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004461void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4462 class DeferredNumberTagI: public LDeferredCode {
4463 public:
4464 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4465 : LDeferredCode(codegen), instr_(instr) { }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004466 virtual void Generate() {
4467 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004468 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004469 SIGNED_INT32);
4470 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004471 virtual LInstruction* instr() { return instr_; }
4472 private:
4473 LNumberTagI* instr_;
4474 };
4475
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004476 Register src = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004477 Register dst = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004478 Register overflow = scratch0();
4479
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004480 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004481 __ SmiTagCheckOverflow(dst, src, overflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004482 __ BranchOnOverflow(deferred->entry(), overflow);
4483 __ bind(deferred->exit());
4484}
4485
4486
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004487void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4488 class DeferredNumberTagU: public LDeferredCode {
4489 public:
4490 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4491 : LDeferredCode(codegen), instr_(instr) { }
4492 virtual void Generate() {
4493 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004494 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004495 UNSIGNED_INT32);
4496 }
4497 virtual LInstruction* instr() { return instr_; }
4498 private:
4499 LNumberTagU* instr_;
4500 };
4501
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004502 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004503 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4504 Register reg = ToRegister(input);
4505
4506 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4507 __ Branch(deferred->entry(), hi, reg, Operand(Smi::kMaxValue));
4508 __ SmiTag(reg, reg);
4509 __ bind(deferred->exit());
4510}
4511
4512
4513void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4514 LOperand* value,
4515 IntegerSignedness signedness) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004516 Label slow;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004517 Register src = ToRegister(value);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004518 Register dst = ToRegister(instr->result());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004519 DoubleRegister dbl_scratch = double_scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004520
4521 // Preserve the value of all registers.
4522 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4523
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004524 Label done;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004525 if (signedness == SIGNED_INT32) {
4526 // There was overflow, so bits 30 and 31 of the original integer
4527 // disagree. Try to allocate a heap number in new space and store
4528 // the value in there. If that fails, call the runtime system.
4529 if (dst.is(src)) {
4530 __ SmiUntag(src, dst);
4531 __ Xor(src, src, Operand(0x80000000));
4532 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004533 __ mtc1(src, dbl_scratch);
4534 __ cvt_d_w(dbl_scratch, dbl_scratch);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004535 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004536 __ mtc1(src, dbl_scratch);
4537 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004538 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004539
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004540 if (FLAG_inline_new) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004541 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
4542 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004543 __ Move(dst, t1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004544 __ Branch(&done);
4545 }
4546
4547 // Slow case: Call the runtime system to do the number allocation.
4548 __ bind(&slow);
4549
4550 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4551 // register is stored, as this register is in the pointer map, but contains an
4552 // integer value.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004553 __ StoreToSafepointRegisterSlot(zero_reg, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004554 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004555 __ Move(dst, v0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004556 __ Subu(dst, dst, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004557
4558 // Done. Put the value in dbl_scratch into the value of the allocated heap
4559 // number.
4560 __ bind(&done);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004561 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004562 __ Addu(dst, dst, kHeapObjectTag);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004563 __ StoreToSafepointRegisterSlot(dst, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004564}
4565
4566
4567void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4568 class DeferredNumberTagD: public LDeferredCode {
4569 public:
4570 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4571 : LDeferredCode(codegen), instr_(instr) { }
4572 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
4573 virtual LInstruction* instr() { return instr_; }
4574 private:
4575 LNumberTagD* instr_;
4576 };
4577
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004578 DoubleRegister input_reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004579 Register scratch = scratch0();
4580 Register reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004581 Register temp1 = ToRegister(instr->temp());
4582 Register temp2 = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004583
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004584 bool convert_hole = false;
4585 HValue* change_input = instr->hydrogen()->value();
4586 if (change_input->IsLoadKeyed()) {
4587 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4588 convert_hole = load->UsesMustHandleHole();
4589 }
4590
4591 Label no_special_nan_handling;
4592 Label done;
4593 if (convert_hole) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004594 DoubleRegister input_reg = ToDoubleRegister(instr->value());
4595 __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
4596 __ Move(reg, scratch0(), input_reg);
4597 Label canonicalize;
4598 __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
4599 __ li(reg, factory()->the_hole_value());
4600 __ Branch(&done);
4601 __ bind(&canonicalize);
4602 __ Move(input_reg,
4603 FixedDoubleArray::canonical_not_the_hole_nan_as_double());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004604 }
4605
4606 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004607 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004608 if (FLAG_inline_new) {
4609 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004610 // We want the untagged address first for performance
4611 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
4612 DONT_TAG_RESULT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004613 } else {
4614 __ Branch(deferred->entry());
4615 }
4616 __ bind(deferred->exit());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004617 __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004618 // Now that we have finished with the object's real address tag it
4619 __ Addu(reg, reg, kHeapObjectTag);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004620 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004621}
4622
4623
4624void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4625 // TODO(3095996): Get rid of this. For now, we need to make the
4626 // result register contain a valid pointer because it is already
4627 // contained in the register pointer map.
4628 Register reg = ToRegister(instr->result());
4629 __ mov(reg, zero_reg);
4630
4631 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4632 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004633 __ Subu(v0, v0, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004634 __ StoreToSafepointRegisterSlot(v0, reg);
4635}
4636
4637
4638void LCodeGen::DoSmiTag(LSmiTag* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004639 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004640 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004641}
4642
4643
4644void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4645 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004646 Register input = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004647 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004648 if (instr->needs_check()) {
4649 STATIC_ASSERT(kHeapObjectTag == 1);
4650 // If the input is a HeapObject, value of scratch won't be zero.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004651 __ And(scratch, input, Operand(kHeapObjectTag));
4652 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004653 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4654 } else {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004655 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004656 }
4657}
4658
4659
4660void LCodeGen::EmitNumberUntagD(Register input_reg,
4661 DoubleRegister result_reg,
4662 bool deoptimize_on_undefined,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004663 bool deoptimize_on_minus_zero,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004664 LEnvironment* env,
4665 NumberUntagDMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004666 Register scratch = scratch0();
4667
4668 Label load_smi, heap_number, done;
4669
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004670 STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE >
4671 NUMBER_CANDIDATE_IS_ANY_TAGGED);
4672 if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004673 // Smi check.
4674 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004675
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004676 // Heap number map check.
4677 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4678 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4679 if (deoptimize_on_undefined) {
4680 DeoptimizeIf(ne, env, scratch, Operand(at));
4681 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004682 Label heap_number, convert;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004683 __ Branch(&heap_number, eq, scratch, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004684
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004685 // Convert undefined (and hole) to NaN.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004686 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004687 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) {
4688 __ Branch(&convert, eq, input_reg, Operand(at));
4689 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
4690 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004691 DeoptimizeIf(ne, env, input_reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004693 __ bind(&convert);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004694 __ LoadRoot(at, Heap::kNanValueRootIndex);
4695 __ ldc1(result_reg, FieldMemOperand(at, HeapNumber::kValueOffset));
4696 __ Branch(&done);
4697
4698 __ bind(&heap_number);
4699 }
4700 // Heap number to double register conversion.
4701 __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4702 if (deoptimize_on_minus_zero) {
4703 __ mfc1(at, result_reg.low());
4704 __ Branch(&done, ne, at, Operand(zero_reg));
4705 __ mfc1(scratch, result_reg.high());
4706 DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask));
4707 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004708 __ Branch(&done);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004709 } else {
4710 __ SmiUntag(scratch, input_reg);
4711 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004712 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004713
4714 // Smi to double register conversion
4715 __ bind(&load_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004716 // scratch: untagged value of input_reg
4717 __ mtc1(scratch, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004718 __ cvt_d_w(result_reg, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004719 __ bind(&done);
4720}
4721
4722
4723void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004724 Register input_reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004725 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004726 Register scratch2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004727 DoubleRegister double_scratch = double_scratch0();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004728 DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004729
4730 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
4731 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
4732
4733 Label done;
4734
4735 // The input is a tagged HeapObject.
4736 // Heap number map check.
4737 __ lw(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4738 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4739 // This 'at' value and scratch1 map value are used for tests in both clauses
4740 // of the if.
4741
4742 if (instr->truncating()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004743 Register scratch3 = ToRegister(instr->temp2());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004744 FPURegister single_scratch = double_scratch.low();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004745 ASSERT(!scratch3.is(input_reg) &&
4746 !scratch3.is(scratch1) &&
4747 !scratch3.is(scratch2));
4748 // Performs a truncating conversion of a floating point number as used by
4749 // the JS bitwise operations.
4750 Label heap_number;
4751 __ Branch(&heap_number, eq, scratch1, Operand(at)); // HeapNumber map?
4752 // Check for undefined. Undefined is converted to zero for truncating
4753 // conversions.
4754 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4755 DeoptimizeIf(ne, instr->environment(), input_reg, Operand(at));
4756 ASSERT(ToRegister(instr->result()).is(input_reg));
4757 __ mov(input_reg, zero_reg);
4758 __ Branch(&done);
4759
4760 __ bind(&heap_number);
4761 __ ldc1(double_scratch2,
4762 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4763 __ EmitECMATruncate(input_reg,
4764 double_scratch2,
4765 single_scratch,
4766 scratch1,
4767 scratch2,
4768 scratch3);
4769 } else {
4770 // Deoptimize if we don't have a heap number.
4771 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at));
4772
4773 // Load the double value.
4774 __ ldc1(double_scratch,
4775 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4776
4777 Register except_flag = scratch2;
4778 __ EmitFPUTruncate(kRoundToZero,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004779 input_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004780 double_scratch,
4781 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004782 double_scratch2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004783 except_flag,
4784 kCheckForInexactConversion);
4785
4786 // Deopt if the operation did not succeed.
4787 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4788
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004789 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4790 __ Branch(&done, ne, input_reg, Operand(zero_reg));
4791
4792 __ mfc1(scratch1, double_scratch.high());
4793 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4794 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4795 }
4796 }
4797 __ bind(&done);
4798}
4799
4800
4801void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
4802 class DeferredTaggedToI: public LDeferredCode {
4803 public:
4804 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4805 : LDeferredCode(codegen), instr_(instr) { }
4806 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4807 virtual LInstruction* instr() { return instr_; }
4808 private:
4809 LTaggedToI* instr_;
4810 };
4811
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004812 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004813 ASSERT(input->IsRegister());
4814 ASSERT(input->Equals(instr->result()));
4815
4816 Register input_reg = ToRegister(input);
4817
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004818 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004819
4820 // Let the deferred code handle the HeapObject case.
4821 __ JumpIfNotSmi(input_reg, deferred->entry());
4822
4823 // Smi to int32 conversion.
4824 __ SmiUntag(input_reg);
4825 __ bind(deferred->exit());
4826}
4827
4828
4829void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004830 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004831 ASSERT(input->IsRegister());
4832 LOperand* result = instr->result();
4833 ASSERT(result->IsDoubleRegister());
4834
4835 Register input_reg = ToRegister(input);
4836 DoubleRegister result_reg = ToDoubleRegister(result);
4837
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004838 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
4839 HValue* value = instr->hydrogen()->value();
4840 if (value->type().IsSmi()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004841 mode = NUMBER_CANDIDATE_IS_SMI;
4842 } else if (value->IsLoadKeyed()) {
4843 HLoadKeyed* load = HLoadKeyed::cast(value);
4844 if (load->UsesMustHandleHole()) {
4845 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
4846 mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004847 }
4848 }
4849 }
4850
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004851 EmitNumberUntagD(input_reg, result_reg,
4852 instr->hydrogen()->deoptimize_on_undefined(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004853 instr->hydrogen()->deoptimize_on_minus_zero(),
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004854 instr->environment(),
4855 mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004856}
4857
4858
4859void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
4860 Register result_reg = ToRegister(instr->result());
4861 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004862 Register scratch2 = ToRegister(instr->temp());
4863 DoubleRegister double_input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004864
4865 if (instr->truncating()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004866 Register scratch3 = ToRegister(instr->temp2());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004867 FPURegister single_scratch = double_scratch0().low();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004868 __ EmitECMATruncate(result_reg,
4869 double_input,
4870 single_scratch,
4871 scratch1,
4872 scratch2,
4873 scratch3);
4874 } else {
4875 Register except_flag = scratch2;
4876
4877 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004878 result_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004879 double_input,
4880 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004881 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004882 except_flag,
4883 kCheckForInexactConversion);
4884
4885 // Deopt if the operation did not succeed (except_flag != 0).
4886 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004887
4888 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4889 Label done;
4890 __ Branch(&done, ne, result_reg, Operand(zero_reg));
4891 __ mfc1(scratch1, double_input.high());
4892 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4893 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4894 __ bind(&done);
4895 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004896 }
4897}
4898
4899
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004900void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
4901 Register result_reg = ToRegister(instr->result());
4902 Register scratch1 = scratch0();
4903 Register scratch2 = ToRegister(instr->temp());
4904 DoubleRegister double_input = ToDoubleRegister(instr->value());
4905
4906 if (instr->truncating()) {
4907 Register scratch3 = ToRegister(instr->temp2());
4908 FPURegister single_scratch = double_scratch0().low();
4909 __ EmitECMATruncate(result_reg,
4910 double_input,
4911 single_scratch,
4912 scratch1,
4913 scratch2,
4914 scratch3);
4915 } else {
4916 Register except_flag = scratch2;
4917
4918 __ EmitFPUTruncate(kRoundToMinusInf,
4919 result_reg,
4920 double_input,
4921 scratch1,
4922 double_scratch0(),
4923 except_flag,
4924 kCheckForInexactConversion);
4925
4926 // Deopt if the operation did not succeed (except_flag != 0).
4927 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4928
4929 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4930 Label done;
4931 __ Branch(&done, ne, result_reg, Operand(zero_reg));
4932 __ mfc1(scratch1, double_input.high());
4933 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4934 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4935 __ bind(&done);
4936 }
4937 }
4938 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1);
4939 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg));
4940}
4941
4942
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004943void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004944 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004945 __ And(at, ToRegister(input), Operand(kSmiTagMask));
4946 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
4947}
4948
4949
4950void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004951 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004952 __ And(at, ToRegister(input), Operand(kSmiTagMask));
4953 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
4954}
4955
4956
4957void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004958 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004959 Register scratch = scratch0();
4960
4961 __ GetObjectType(input, scratch, scratch);
4962
4963 if (instr->hydrogen()->is_interval_check()) {
4964 InstanceType first;
4965 InstanceType last;
4966 instr->hydrogen()->GetCheckInterval(&first, &last);
4967
4968 // If there is only one type in the interval check for equality.
4969 if (first == last) {
4970 DeoptimizeIf(ne, instr->environment(), scratch, Operand(first));
4971 } else {
4972 DeoptimizeIf(lo, instr->environment(), scratch, Operand(first));
4973 // Omit check for the last type.
4974 if (last != LAST_TYPE) {
4975 DeoptimizeIf(hi, instr->environment(), scratch, Operand(last));
4976 }
4977 }
4978 } else {
4979 uint8_t mask;
4980 uint8_t tag;
4981 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4982
4983 if (IsPowerOf2(mask)) {
4984 ASSERT(tag == 0 || IsPowerOf2(tag));
4985 __ And(at, scratch, mask);
4986 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment(),
4987 at, Operand(zero_reg));
4988 } else {
4989 __ And(scratch, scratch, Operand(mask));
4990 DeoptimizeIf(ne, instr->environment(), scratch, Operand(tag));
4991 }
4992 }
4993}
4994
4995
4996void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004997 Register reg = ToRegister(instr->value());
4998 Handle<JSFunction> target = instr->hydrogen()->target();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004999 ALLOW_HANDLE_DEREF(isolate(), "smi check");
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005000 if (isolate()->heap()->InNewSpace(*target)) {
5001 Register reg = ToRegister(instr->value());
5002 Handle<JSGlobalPropertyCell> cell =
5003 isolate()->factory()->NewJSGlobalPropertyCell(target);
5004 __ li(at, Operand(Handle<Object>(cell)));
5005 __ lw(at, FieldMemOperand(at, JSGlobalPropertyCell::kValueOffset));
5006 DeoptimizeIf(ne, instr->environment(), reg,
5007 Operand(at));
5008 } else {
5009 DeoptimizeIf(ne, instr->environment(), reg,
5010 Operand(target));
5011 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005012}
5013
5014
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005015void LCodeGen::DoCheckMapCommon(Register map_reg,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005016 Handle<Map> map,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005017 LEnvironment* env) {
5018 Label success;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005019 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005020 DeoptimizeIf(al, env);
5021 __ bind(&success);
5022}
5023
5024
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005025void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005026 Register map_reg = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005027 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005028 ASSERT(input->IsRegister());
5029 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005030 Label success;
5031 SmallMapList* map_set = instr->hydrogen()->map_set();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005032 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005033 for (int i = 0; i < map_set->length() - 1; i++) {
5034 Handle<Map> map = map_set->at(i);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005035 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005036 }
5037 Handle<Map> map = map_set->last();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005038 DoCheckMapCommon(map_reg, map, instr->environment());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005039 __ bind(&success);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005040}
5041
5042
5043void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5044 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
5045 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005046 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005047 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
5048}
5049
5050
5051void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5052 Register unclamped_reg = ToRegister(instr->unclamped());
5053 Register result_reg = ToRegister(instr->result());
5054 __ ClampUint8(result_reg, unclamped_reg);
5055}
5056
5057
5058void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5059 Register scratch = scratch0();
5060 Register input_reg = ToRegister(instr->unclamped());
5061 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005062 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005063 Label is_smi, done, heap_number;
5064
5065 // Both smi and heap number cases are handled.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005066 __ UntagAndJumpIfSmi(scratch, input_reg, &is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005067
5068 // Check for heap number
5069 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
5070 __ Branch(&heap_number, eq, scratch, Operand(factory()->heap_number_map()));
5071
5072 // Check for undefined. Undefined is converted to zero for clamping
5073 // conversions.
5074 DeoptimizeIf(ne, instr->environment(), input_reg,
5075 Operand(factory()->undefined_value()));
5076 __ mov(result_reg, zero_reg);
5077 __ jmp(&done);
5078
5079 // Heap number
5080 __ bind(&heap_number);
5081 __ ldc1(double_scratch0(), FieldMemOperand(input_reg,
5082 HeapNumber::kValueOffset));
5083 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
5084 __ jmp(&done);
5085
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005086 __ bind(&is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005087 __ ClampUint8(result_reg, scratch);
5088
5089 __ bind(&done);
5090}
5091
5092
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005093void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005094 Register prototype_reg = ToRegister(instr->temp());
5095 Register map_reg = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005096
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005097 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5098 ZoneList<Handle<Map> >* maps = instr->maps();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005099
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005100 ASSERT(prototypes->length() == maps->length());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005101
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005102 if (instr->hydrogen()->CanOmitPrototypeChecks()) {
5103 for (int i = 0; i < maps->length(); i++) {
5104 prototype_maps_.Add(maps->at(i), info()->zone());
5105 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005106 } else {
5107 for (int i = 0; i < prototypes->length(); i++) {
5108 __ LoadHeapObject(prototype_reg, prototypes->at(i));
5109 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005110 DoCheckMapCommon(map_reg, maps->at(i), instr->environment());
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005111 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005112 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005113}
5114
5115
ulan@chromium.org967e2702012-02-28 09:49:15 +00005116void LCodeGen::DoAllocateObject(LAllocateObject* instr) {
5117 class DeferredAllocateObject: public LDeferredCode {
5118 public:
5119 DeferredAllocateObject(LCodeGen* codegen, LAllocateObject* instr)
5120 : LDeferredCode(codegen), instr_(instr) { }
5121 virtual void Generate() { codegen()->DoDeferredAllocateObject(instr_); }
5122 virtual LInstruction* instr() { return instr_; }
5123 private:
5124 LAllocateObject* instr_;
5125 };
5126
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005127 DeferredAllocateObject* deferred =
5128 new(zone()) DeferredAllocateObject(this, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005129
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005130 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005131 Register scratch = ToRegister(instr->temp());
5132 Register scratch2 = ToRegister(instr->temp2());
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005133 Handle<JSFunction> constructor = instr->hydrogen()->constructor();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005134 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005135 int instance_size = initial_map->instance_size();
5136 ASSERT(initial_map->pre_allocated_property_fields() +
5137 initial_map->unused_property_fields() -
5138 initial_map->inobject_properties() == 0);
5139
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005140 __ Allocate(instance_size, result, scratch, scratch2, deferred->entry(),
5141 TAG_OBJECT);
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005142
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005143 __ bind(deferred->exit());
5144 if (FLAG_debug_code) {
5145 Label is_in_new_space;
5146 __ JumpIfInNewSpace(result, scratch, &is_in_new_space);
5147 __ Abort("Allocated object is not in new-space");
5148 __ bind(&is_in_new_space);
5149 }
5150
fschneider@chromium.org35814e52012-03-01 15:43:35 +00005151 // Load the initial map.
5152 Register map = scratch;
5153 __ LoadHeapObject(map, constructor);
5154 __ lw(map, FieldMemOperand(map, JSFunction::kPrototypeOrInitialMapOffset));
5155
5156 // Initialize map and fields of the newly allocated object.
5157 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE);
5158 __ sw(map, FieldMemOperand(result, JSObject::kMapOffset));
5159 __ LoadRoot(scratch, Heap::kEmptyFixedArrayRootIndex);
5160 __ sw(scratch, FieldMemOperand(result, JSObject::kElementsOffset));
5161 __ sw(scratch, FieldMemOperand(result, JSObject::kPropertiesOffset));
5162 if (initial_map->inobject_properties() != 0) {
5163 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
5164 for (int i = 0; i < initial_map->inobject_properties(); i++) {
5165 int property_offset = JSObject::kHeaderSize + i * kPointerSize;
5166 __ sw(scratch, FieldMemOperand(result, property_offset));
5167 }
5168 }
ulan@chromium.org967e2702012-02-28 09:49:15 +00005169}
5170
5171
5172void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) {
5173 Register result = ToRegister(instr->result());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005174 Handle<Map> initial_map = instr->hydrogen()->constructor_initial_map();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005175 int instance_size = initial_map->instance_size();
ulan@chromium.org967e2702012-02-28 09:49:15 +00005176
5177 // TODO(3095996): Get rid of this. For now, we need to make the
5178 // result register contain a valid pointer because it is already
5179 // contained in the register pointer map.
5180 __ mov(result, zero_reg);
5181
5182 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005183 __ li(a0, Operand(Smi::FromInt(instance_size)));
ulan@chromium.org967e2702012-02-28 09:49:15 +00005184 __ push(a0);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00005185 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
ulan@chromium.org967e2702012-02-28 09:49:15 +00005186 __ StoreToSafepointRegisterSlot(v0, result);
5187}
5188
5189
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005190void LCodeGen::DoAllocate(LAllocate* instr) {
5191 class DeferredAllocate: public LDeferredCode {
5192 public:
5193 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5194 : LDeferredCode(codegen), instr_(instr) { }
5195 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5196 virtual LInstruction* instr() { return instr_; }
5197 private:
5198 LAllocate* instr_;
5199 };
5200
5201 DeferredAllocate* deferred =
5202 new(zone()) DeferredAllocate(this, instr);
5203
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005204 Register result = ToRegister(instr->result());
5205 Register scratch = ToRegister(instr->temp1());
5206 Register scratch2 = ToRegister(instr->temp2());
5207
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005208 // Allocate memory for the object.
5209 AllocationFlags flags = TAG_OBJECT;
5210 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5211 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5212 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005213 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
5214 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
5215 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005216 if (instr->size()->IsConstantOperand()) {
5217 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005218 __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005219 } else {
5220 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005221 __ Allocate(size,
5222 result,
5223 scratch,
5224 scratch2,
5225 deferred->entry(),
5226 flags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005227 }
5228
5229 __ bind(deferred->exit());
5230}
5231
5232
5233void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005234 Register result = ToRegister(instr->result());
5235
5236 // TODO(3095996): Get rid of this. For now, we need to make the
5237 // result register contain a valid pointer because it is already
5238 // contained in the register pointer map.
5239 __ mov(result, zero_reg);
5240
5241 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005242 if (instr->size()->IsRegister()) {
5243 Register size = ToRegister(instr->size());
5244 ASSERT(!size.is(result));
5245 __ SmiTag(size);
5246 __ push(size);
5247 } else {
5248 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5249 __ Push(Smi::FromInt(size));
5250 }
5251
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005252 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
5253 CallRuntimeFromDeferred(
5254 Runtime::kAllocateInOldPointerSpace, 1, instr);
5255 } else {
5256 CallRuntimeFromDeferred(
5257 Runtime::kAllocateInNewSpace, 1, instr);
5258 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005259 __ StoreToSafepointRegisterSlot(v0, result);
5260}
5261
5262
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005263void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005264 ASSERT(ToRegister(instr->value()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005265 ASSERT(ToRegister(instr->result()).is(v0));
5266 __ push(a0);
5267 CallRuntime(Runtime::kToFastProperties, 1, instr);
5268}
5269
5270
5271void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
5272 Label materialized;
5273 // Registers will be used as follows:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005274 // t3 = literals array.
5275 // a1 = regexp literal.
5276 // a0 = regexp literal clone.
5277 // a2 and t0-t2 are used as temporaries.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005278 int literal_offset =
5279 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5280 __ LoadHeapObject(t3, instr->hydrogen()->literals());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005281 __ lw(a1, FieldMemOperand(t3, literal_offset));
5282 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5283 __ Branch(&materialized, ne, a1, Operand(at));
5284
5285 // Create regexp literal using runtime function
5286 // Result will be in v0.
5287 __ li(t2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
5288 __ li(t1, Operand(instr->hydrogen()->pattern()));
5289 __ li(t0, Operand(instr->hydrogen()->flags()));
5290 __ Push(t3, t2, t1, t0);
5291 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5292 __ mov(a1, v0);
5293
5294 __ bind(&materialized);
5295 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5296 Label allocated, runtime_allocate;
5297
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005298 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005299 __ jmp(&allocated);
5300
5301 __ bind(&runtime_allocate);
5302 __ li(a0, Operand(Smi::FromInt(size)));
5303 __ Push(a1, a0);
5304 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5305 __ pop(a1);
5306
5307 __ bind(&allocated);
5308 // Copy the content into the newly allocated memory.
5309 // (Unroll copy loop once for better throughput).
5310 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5311 __ lw(a3, FieldMemOperand(a1, i));
5312 __ lw(a2, FieldMemOperand(a1, i + kPointerSize));
5313 __ sw(a3, FieldMemOperand(v0, i));
5314 __ sw(a2, FieldMemOperand(v0, i + kPointerSize));
5315 }
5316 if ((size % (2 * kPointerSize)) != 0) {
5317 __ lw(a3, FieldMemOperand(a1, size - kPointerSize));
5318 __ sw(a3, FieldMemOperand(v0, size - kPointerSize));
5319 }
5320}
5321
5322
5323void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
5324 // Use the fast case closure allocation code that allocates in new
5325 // space for nested functions that don't need literals cloning.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005326 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005327 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5328 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5329 instr->hydrogen()->is_generator());
5330 __ li(a1, Operand(instr->hydrogen()->shared_info()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005331 __ push(a1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005332 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005333 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005334 __ li(a2, Operand(instr->hydrogen()->shared_info()));
5335 __ li(a1, Operand(pretenure ? factory()->true_value()
5336 : factory()->false_value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005337 __ Push(cp, a2, a1);
5338 CallRuntime(Runtime::kNewClosure, 3, instr);
5339 }
5340}
5341
5342
5343void LCodeGen::DoTypeof(LTypeof* instr) {
5344 ASSERT(ToRegister(instr->result()).is(v0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005345 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005346 __ push(input);
5347 CallRuntime(Runtime::kTypeof, 1, instr);
5348}
5349
5350
5351void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005352 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005353 int true_block = chunk_->LookupDestination(instr->true_block_id());
5354 int false_block = chunk_->LookupDestination(instr->false_block_id());
5355 Label* true_label = chunk_->GetAssemblyLabel(true_block);
5356 Label* false_label = chunk_->GetAssemblyLabel(false_block);
5357
5358 Register cmp1 = no_reg;
5359 Operand cmp2 = Operand(no_reg);
5360
5361 Condition final_branch_condition = EmitTypeofIs(true_label,
5362 false_label,
5363 input,
5364 instr->type_literal(),
5365 cmp1,
5366 cmp2);
5367
5368 ASSERT(cmp1.is_valid());
5369 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid());
5370
5371 if (final_branch_condition != kNoCondition) {
5372 EmitBranch(true_block, false_block, final_branch_condition, cmp1, cmp2);
5373 }
5374}
5375
5376
5377Condition LCodeGen::EmitTypeofIs(Label* true_label,
5378 Label* false_label,
5379 Register input,
5380 Handle<String> type_name,
5381 Register& cmp1,
5382 Operand& cmp2) {
5383 // This function utilizes the delay slot heavily. This is used to load
5384 // values that are always usable without depending on the type of the input
5385 // register.
5386 Condition final_branch_condition = kNoCondition;
5387 Register scratch = scratch0();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005388 if (type_name->Equals(heap()->number_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005389 __ JumpIfSmi(input, true_label);
5390 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5391 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
5392 cmp1 = input;
5393 cmp2 = Operand(at);
5394 final_branch_condition = eq;
5395
ulan@chromium.org750145a2013-03-07 15:14:13 +00005396 } else if (type_name->Equals(heap()->string_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005397 __ JumpIfSmi(input, false_label);
5398 __ GetObjectType(input, input, scratch);
5399 __ Branch(USE_DELAY_SLOT, false_label,
5400 ge, scratch, Operand(FIRST_NONSTRING_TYPE));
5401 // input is an object so we can load the BitFieldOffset even if we take the
5402 // other branch.
5403 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5404 __ And(at, at, 1 << Map::kIsUndetectable);
5405 cmp1 = at;
5406 cmp2 = Operand(zero_reg);
5407 final_branch_condition = eq;
5408
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005409 } else if (type_name->Equals(heap()->symbol_string())) {
5410 __ JumpIfSmi(input, false_label);
5411 __ GetObjectType(input, input, scratch);
5412 cmp1 = scratch;
5413 cmp2 = Operand(SYMBOL_TYPE);
5414 final_branch_condition = eq;
5415
ulan@chromium.org750145a2013-03-07 15:14:13 +00005416 } else if (type_name->Equals(heap()->boolean_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005417 __ LoadRoot(at, Heap::kTrueValueRootIndex);
5418 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5419 __ LoadRoot(at, Heap::kFalseValueRootIndex);
5420 cmp1 = at;
5421 cmp2 = Operand(input);
5422 final_branch_condition = eq;
5423
ulan@chromium.org750145a2013-03-07 15:14:13 +00005424 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005425 __ LoadRoot(at, Heap::kNullValueRootIndex);
5426 cmp1 = at;
5427 cmp2 = Operand(input);
5428 final_branch_condition = eq;
5429
ulan@chromium.org750145a2013-03-07 15:14:13 +00005430 } else if (type_name->Equals(heap()->undefined_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005431 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5432 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5433 // The first instruction of JumpIfSmi is an And - it is safe in the delay
5434 // slot.
5435 __ JumpIfSmi(input, false_label);
5436 // Check for undetectable objects => true.
5437 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5438 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5439 __ And(at, at, 1 << Map::kIsUndetectable);
5440 cmp1 = at;
5441 cmp2 = Operand(zero_reg);
5442 final_branch_condition = ne;
5443
ulan@chromium.org750145a2013-03-07 15:14:13 +00005444 } else if (type_name->Equals(heap()->function_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005445 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5446 __ JumpIfSmi(input, false_label);
5447 __ GetObjectType(input, scratch, input);
5448 __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE));
5449 cmp1 = input;
5450 cmp2 = Operand(JS_FUNCTION_PROXY_TYPE);
5451 final_branch_condition = eq;
5452
ulan@chromium.org750145a2013-03-07 15:14:13 +00005453 } else if (type_name->Equals(heap()->object_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005454 __ JumpIfSmi(input, false_label);
5455 if (!FLAG_harmony_typeof) {
5456 __ LoadRoot(at, Heap::kNullValueRootIndex);
5457 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5458 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005459 Register map = input;
5460 __ GetObjectType(input, map, scratch);
5461 __ Branch(false_label,
5462 lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005463 __ Branch(USE_DELAY_SLOT, false_label,
5464 gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005465 // map is still valid, so the BitField can be loaded in delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005466 // Check for undetectable objects => false.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005467 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005468 __ And(at, at, 1 << Map::kIsUndetectable);
5469 cmp1 = at;
5470 cmp2 = Operand(zero_reg);
5471 final_branch_condition = eq;
5472
5473 } else {
5474 cmp1 = at;
5475 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion.
5476 __ Branch(false_label);
5477 }
5478
5479 return final_branch_condition;
5480}
5481
5482
5483void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005484 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005485 int true_block = chunk_->LookupDestination(instr->true_block_id());
5486 int false_block = chunk_->LookupDestination(instr->false_block_id());
5487
5488 EmitIsConstructCall(temp1, scratch0());
5489
5490 EmitBranch(true_block, false_block, eq, temp1,
5491 Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
5492}
5493
5494
5495void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
5496 ASSERT(!temp1.is(temp2));
5497 // Get the frame pointer for the calling frame.
5498 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5499
5500 // Skip the arguments adaptor frame if it exists.
5501 Label check_frame_marker;
5502 __ lw(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
5503 __ Branch(&check_frame_marker, ne, temp2,
5504 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
5505 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
5506
5507 // Check the marker in the calling frame.
5508 __ bind(&check_frame_marker);
5509 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
5510}
5511
5512
erikcorry0ad885c2011-11-21 13:51:57 +00005513void LCodeGen::EnsureSpaceForLazyDeopt() {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005514 if (info()->IsStub()) return;
erikcorry0ad885c2011-11-21 13:51:57 +00005515 // Ensure that we have enough space after the previous lazy-bailout
5516 // instruction for patching the code here.
5517 int current_pc = masm()->pc_offset();
5518 int patch_size = Deoptimizer::patch_size();
5519 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5520 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
5521 ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
5522 while (padding_size > 0) {
5523 __ nop();
5524 padding_size -= Assembler::kInstrSize;
5525 }
5526 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005527 last_lazy_deopt_pc_ = masm()->pc_offset();
erikcorry0ad885c2011-11-21 13:51:57 +00005528}
5529
5530
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005531void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005532 EnsureSpaceForLazyDeopt();
5533 ASSERT(instr->HasEnvironment());
5534 LEnvironment* env = instr->environment();
5535 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5536 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005537}
5538
5539
5540void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
palfia@homejinni.com04109732013-05-15 09:50:32 +00005541 if (instr->hydrogen_value()->IsSoftDeoptimize()) {
5542 SoftDeoptimize(instr->environment(), zero_reg, Operand(zero_reg));
5543 } else {
5544 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
5545 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005546}
5547
5548
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005549void LCodeGen::DoDummyUse(LDummyUse* instr) {
5550 // Nothing to see here, move on!
5551}
5552
5553
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005554void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
5555 Register object = ToRegister(instr->object());
5556 Register key = ToRegister(instr->key());
5557 Register strict = scratch0();
5558 __ li(strict, Operand(Smi::FromInt(strict_mode_flag())));
5559 __ Push(object, key, strict);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00005560 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005561 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005562 RecordPosition(pointers->position());
erikcorry0ad885c2011-11-21 13:51:57 +00005563 SafepointGenerator safepoint_generator(
5564 this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005565 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
5566}
5567
5568
5569void LCodeGen::DoIn(LIn* instr) {
5570 Register obj = ToRegister(instr->object());
5571 Register key = ToRegister(instr->key());
5572 __ Push(key, obj);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00005573 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005574 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005575 RecordPosition(pointers->position());
erikcorry0ad885c2011-11-21 13:51:57 +00005576 SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005577 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
5578}
5579
5580
5581void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005582 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
5583 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5584 RecordSafepointWithLazyDeopt(
5585 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5586 ASSERT(instr->HasEnvironment());
5587 LEnvironment* env = instr->environment();
5588 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005589}
5590
5591
5592void LCodeGen::DoStackCheck(LStackCheck* instr) {
5593 class DeferredStackCheck: public LDeferredCode {
5594 public:
5595 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5596 : LDeferredCode(codegen), instr_(instr) { }
5597 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
5598 virtual LInstruction* instr() { return instr_; }
5599 private:
5600 LStackCheck* instr_;
5601 };
5602
erikcorry0ad885c2011-11-21 13:51:57 +00005603 ASSERT(instr->HasEnvironment());
5604 LEnvironment* env = instr->environment();
5605 // There is no LLazyBailout instruction for stack-checks. We have to
5606 // prepare for lazy deoptimization explicitly here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005607 if (instr->hydrogen()->is_function_entry()) {
5608 // Perform stack overflow check.
5609 Label done;
5610 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5611 __ Branch(&done, hs, sp, Operand(at));
5612 StackCheckStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005613 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erikcorry0ad885c2011-11-21 13:51:57 +00005614 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005615 __ bind(&done);
erikcorry0ad885c2011-11-21 13:51:57 +00005616 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5617 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005618 } else {
5619 ASSERT(instr->hydrogen()->is_backwards_branch());
5620 // Perform stack overflow check if this goto needs it before jumping.
5621 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005622 new(zone()) DeferredStackCheck(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005623 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5624 __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at));
erikcorry0ad885c2011-11-21 13:51:57 +00005625 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005626 __ bind(instr->done_label());
5627 deferred_stack_check->SetExit(instr->done_label());
erikcorry0ad885c2011-11-21 13:51:57 +00005628 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5629 // Don't record a deoptimization index for the safepoint here.
5630 // This will be done explicitly when emitting call and the safepoint in
5631 // the deferred code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005632 }
5633}
5634
5635
5636void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5637 // This is a pseudo-instruction that ensures that the environment here is
5638 // properly registered for deoptimization and records the assembler's PC
5639 // offset.
5640 LEnvironment* environment = instr->environment();
5641 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
5642 instr->SpilledDoubleRegisterArray());
5643
5644 // If the environment were already registered, we would have no way of
5645 // backpatching it with the spill slot operands.
5646 ASSERT(!environment->HasBeenRegistered());
erikcorry0ad885c2011-11-21 13:51:57 +00005647 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005648 ASSERT(osr_pc_offset_ == -1);
5649 osr_pc_offset_ = masm()->pc_offset();
5650}
5651
5652
ulan@chromium.org812308e2012-02-29 15:58:45 +00005653void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5654 Register result = ToRegister(instr->result());
5655 Register object = ToRegister(instr->object());
5656 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5657 DeoptimizeIf(eq, instr->environment(), object, Operand(at));
5658
5659 Register null_value = t1;
5660 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5661 DeoptimizeIf(eq, instr->environment(), object, Operand(null_value));
5662
5663 __ And(at, object, kSmiTagMask);
5664 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5665
5666 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5667 __ GetObjectType(object, a1, a1);
5668 DeoptimizeIf(le, instr->environment(), a1, Operand(LAST_JS_PROXY_TYPE));
5669
5670 Label use_cache, call_runtime;
5671 ASSERT(object.is(a0));
5672 __ CheckEnumCache(null_value, &call_runtime);
5673
5674 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
5675 __ Branch(&use_cache);
5676
5677 // Get the set of properties to enumerate.
5678 __ bind(&call_runtime);
5679 __ push(object);
5680 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5681
5682 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
5683 ASSERT(result.is(v0));
5684 __ LoadRoot(at, Heap::kMetaMapRootIndex);
5685 DeoptimizeIf(ne, instr->environment(), a1, Operand(at));
5686 __ bind(&use_cache);
5687}
5688
5689
5690void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5691 Register map = ToRegister(instr->map());
5692 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005693 Label load_cache, done;
5694 __ EnumLength(result, map);
5695 __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0)));
5696 __ li(result, Operand(isolate()->factory()->empty_fixed_array()));
5697 __ jmp(&done);
5698
5699 __ bind(&load_cache);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005700 __ LoadInstanceDescriptors(map, result);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005701 __ lw(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005702 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +00005703 __ lw(result,
5704 FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
5705 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005706
5707 __ bind(&done);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005708}
5709
5710
5711void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5712 Register object = ToRegister(instr->value());
5713 Register map = ToRegister(instr->map());
5714 __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
5715 DeoptimizeIf(ne, instr->environment(), map, Operand(scratch0()));
5716}
5717
5718
5719void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5720 Register object = ToRegister(instr->object());
5721 Register index = ToRegister(instr->index());
5722 Register result = ToRegister(instr->result());
5723 Register scratch = scratch0();
5724
5725 Label out_of_object, done;
5726 __ Branch(USE_DELAY_SLOT, &out_of_object, lt, index, Operand(zero_reg));
5727 __ sll(scratch, index, kPointerSizeLog2 - kSmiTagSize); // In delay slot.
5728
5729 STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
5730 __ Addu(scratch, object, scratch);
5731 __ lw(result, FieldMemOperand(scratch, JSObject::kHeaderSize));
5732
5733 __ Branch(&done);
5734
5735 __ bind(&out_of_object);
5736 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
5737 // Index is equal to negated out of object property index plus 1.
5738 __ Subu(scratch, result, scratch);
5739 __ lw(result, FieldMemOperand(scratch,
5740 FixedArray::kHeaderSize - kPointerSize));
5741 __ bind(&done);
5742}
5743
5744
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005745#undef __
5746
5747} } // namespace v8::internal