blob: 565c2506ba5ef85a67dacf021568016424570e0a [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() {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000065 LPhase 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);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000090 info()->CommitDependencies(code);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000091}
92
93
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000094void LChunkBuilder::Abort(const char* reason) {
95 info()->set_bailout_reason(reason);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000096 status_ = ABORTED;
97}
98
99
100void LCodeGen::Comment(const char* format, ...) {
101 if (!FLAG_code_comments) return;
102 char buffer[4 * KB];
103 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
104 va_list arguments;
105 va_start(arguments, format);
106 builder.AddFormattedList(format, arguments);
107 va_end(arguments);
108
109 // Copy the string before recording it in the assembler to avoid
110 // issues when the stack allocated buffer goes out of scope.
111 size_t length = builder.position();
112 Vector<char> copy = Vector<char>::New(length + 1);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000113 OS::MemCopy(copy.start(), builder.Finalize(), copy.length());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000114 masm()->RecordComment(copy.start());
115}
116
117
118bool LCodeGen::GeneratePrologue() {
119 ASSERT(is_generating());
120
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000121 if (info()->IsOptimizing()) {
122 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
danno@chromium.org129d3982012-07-25 15:01:47 +0000123
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124#ifdef DEBUG
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000125 if (strlen(FLAG_stop_at) > 0 &&
126 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
127 __ stop("stop_at");
128 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000129#endif
130
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000131 // a1: Callee's JS function.
132 // cp: Callee's context.
133 // fp: Caller's frame pointer.
134 // lr: Caller's pc.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000135
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000136 // Strict mode functions and builtins need to replace the receiver
137 // with undefined when called as functions (without an explicit
138 // receiver object). r5 is zero for method calls and non-zero for
139 // function calls.
140 if (!info_->is_classic_mode() || info_->is_native()) {
141 Label ok;
142 __ Branch(&ok, eq, t1, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000143
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000144 int receiver_offset = scope()->num_parameters() * kPointerSize;
145 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
146 __ sw(a2, MemOperand(sp, receiver_offset));
147 __ bind(&ok);
148 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000149 }
150
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000151 info()->set_prologue_offset(masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000152 if (NeedsEagerFrame()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000153 if (info()->IsStub()) {
154 __ Push(ra, fp, cp);
155 __ Push(Smi::FromInt(StackFrame::STUB));
156 // Adjust FP to point to saved FP.
157 __ Addu(fp, sp, Operand(2 * kPointerSize));
158 } else {
159 // The following three instructions must remain together and unmodified
160 // for code aging to work properly.
161 __ Push(ra, fp, cp, a1);
162 // Add unused load of ip to ensure prologue sequence is identical for
163 // full-codegen and lithium-codegen.
164 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
165 // Adj. FP to point to saved FP.
166 __ Addu(fp, sp, Operand(2 * kPointerSize));
167 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000168 frame_is_built_ = true;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000169 info_->AddNoFrameRange(0, masm_->pc_offset());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000170 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000171
172 // Reserve space for the stack slots needed by the code.
173 int slots = GetStackSlotCount();
174 if (slots > 0) {
175 if (FLAG_debug_code) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000176 __ Subu(sp, sp, Operand(slots * kPointerSize));
177 __ push(a0);
178 __ push(a1);
179 __ Addu(a0, sp, Operand(slots * kPointerSize));
180 __ li(a1, Operand(kSlotsZapValue));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000181 Label loop;
182 __ bind(&loop);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000183 __ Subu(a0, a0, Operand(kPointerSize));
184 __ sw(a1, MemOperand(a0, 2 * kPointerSize));
185 __ Branch(&loop, ne, a0, Operand(sp));
186 __ pop(a1);
187 __ pop(a0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000188 } else {
189 __ Subu(sp, sp, Operand(slots * kPointerSize));
190 }
191 }
192
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000193 if (info()->saves_caller_doubles()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000194 Comment(";;; Save clobbered callee double registers");
195 int count = 0;
196 BitVector* doubles = chunk()->allocated_double_registers();
197 BitVector::Iterator save_iterator(doubles);
198 while (!save_iterator.Done()) {
199 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
200 MemOperand(sp, count * kDoubleSize));
201 save_iterator.Advance();
202 count++;
203 }
204 }
205
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000206 // Possibly allocate a local context.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000207 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000208 if (heap_slots > 0) {
209 Comment(";;; Allocate local context");
210 // Argument to NewContext is the function, which is in a1.
211 __ push(a1);
212 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
213 FastNewContextStub stub(heap_slots);
214 __ CallStub(&stub);
215 } else {
216 __ CallRuntime(Runtime::kNewFunctionContext, 1);
217 }
erikcorry0ad885c2011-11-21 13:51:57 +0000218 RecordSafepoint(Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000219 // Context is returned in both v0 and cp. It replaces the context
220 // passed to us. It's saved in the stack and kept live in cp.
221 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
222 // Copy any necessary parameters into the context.
223 int num_parameters = scope()->num_parameters();
224 for (int i = 0; i < num_parameters; i++) {
225 Variable* var = scope()->parameter(i);
226 if (var->IsContextSlot()) {
227 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
228 (num_parameters - 1 - i) * kPointerSize;
229 // Load parameter from stack.
230 __ lw(a0, MemOperand(fp, parameter_offset));
231 // Store it in the context.
232 MemOperand target = ContextOperand(cp, var->index());
233 __ sw(a0, target);
234 // Update the write barrier. This clobbers a3 and a0.
235 __ RecordWriteContextSlot(
danno@chromium.orgc99cd482013-03-21 15:26:42 +0000236 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000237 }
238 }
239 Comment(";;; End allocate local context");
240 }
241
242 // Trace the call.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000243 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000244 __ CallRuntime(Runtime::kTraceEnter, 0);
245 }
246 return !is_aborted();
247}
248
249
250bool LCodeGen::GenerateBody() {
251 ASSERT(is_generating());
252 bool emit_instructions = true;
253 for (current_instruction_ = 0;
254 !is_aborted() && current_instruction_ < instructions_->length();
255 current_instruction_++) {
256 LInstruction* instr = instructions_->at(current_instruction_);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000257
258 // Don't emit code for basic blocks with a replacement.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000259 if (instr->IsLabel()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000260 emit_instructions = !LLabel::cast(instr)->HasReplacement();
261 }
262 if (!emit_instructions) continue;
263
264 if (FLAG_code_comments && instr->HasInterestingComment(this)) {
265 Comment(";;; <@%d,#%d> %s",
266 current_instruction_,
267 instr->hydrogen_value()->id(),
268 instr->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000269 }
270
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000271 instr->CompileToNative(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000272 }
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000273 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000274 return !is_aborted();
275}
276
277
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000278bool LCodeGen::GenerateDeferredCode() {
279 ASSERT(is_generating());
280 if (deferred_.length() > 0) {
281 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
282 LDeferredCode* code = deferred_[i];
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000283 Comment(";;; <@%d,#%d> "
284 "-------------------- Deferred %s --------------------",
285 code->instruction_index(),
286 code->instr()->hydrogen_value()->id(),
287 code->instr()->Mnemonic());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000288 __ bind(code->entry());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000289 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000290 Comment(";;; Build frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000291 ASSERT(!frame_is_built_);
292 ASSERT(info()->IsStub());
293 frame_is_built_ = true;
294 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
295 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
296 __ push(scratch0());
297 __ Addu(fp, sp, Operand(2 * kPointerSize));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000298 Comment(";;; Deferred code");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000299 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000300 code->Generate();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000301 if (NeedsDeferredFrame()) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000302 Comment(";;; Destroy frame");
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000303 ASSERT(frame_is_built_);
304 __ pop(at);
305 __ MultiPop(cp.bit() | fp.bit() | ra.bit());
306 frame_is_built_ = false;
307 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000308 __ jmp(code->exit());
309 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000310 }
311 // Deferred code is the last part of the instruction sequence. Mark
312 // the generated code as done unless we bailed out.
313 if (!is_aborted()) status_ = DONE;
314 return !is_aborted();
315}
316
317
318bool LCodeGen::GenerateDeoptJumpTable() {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000319 // Check that the jump table is accessible from everywhere in the function
320 // code, i.e. that offsets to the table can be encoded in the 16bit signed
321 // immediate of a branch instruction.
322 // To simplify we consider the code size from the first instruction to the
323 // end of the jump table.
324 if (!is_int16((masm()->pc_offset() / Assembler::kInstrSize) +
325 deopt_jump_table_.length() * 12)) {
326 Abort("Generated code is too large");
327 }
328
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000329 if (deopt_jump_table_.length() > 0) {
330 Comment(";;; -------------------- Jump table --------------------");
331 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000332 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000333 Label table_start;
334 __ bind(&table_start);
danno@chromium.org169691d2013-07-15 08:01:13 +0000335 Label needs_frame;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000336 for (int i = 0; i < deopt_jump_table_.length(); i++) {
337 __ bind(&deopt_jump_table_[i].label);
338 Address entry = deopt_jump_table_[i].address;
palfia@homejinni.com04109732013-05-15 09:50:32 +0000339 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000340 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000341 if (id == Deoptimizer::kNotDeoptimizationEntry) {
342 Comment(";;; jump table entry %d.", i);
343 } else {
344 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
345 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000346 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry)));
347 if (deopt_jump_table_[i].needs_frame) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000348 if (needs_frame.is_bound()) {
349 __ Branch(&needs_frame);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000350 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000351 __ bind(&needs_frame);
352 __ MultiPush(cp.bit() | fp.bit() | ra.bit());
353 // This variant of deopt can only be used with stubs. Since we don't
354 // have a function pointer to install in the stack frame that we're
355 // building, install a special marker there instead.
356 ASSERT(info()->IsStub());
357 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB)));
358 __ push(scratch0());
359 __ Addu(fp, sp, Operand(2 * kPointerSize));
360 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000361 }
362 } else {
danno@chromium.org169691d2013-07-15 08:01:13 +0000363 __ Call(t9);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000364 }
365 }
366 __ RecordComment("]");
367
368 // The deoptimization jump table is the last part of the instruction
369 // sequence. Mark the generated code as done unless we bailed out.
370 if (!is_aborted()) status_ = DONE;
371 return !is_aborted();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000372}
373
374
375bool LCodeGen::GenerateSafepointTable() {
376 ASSERT(is_done());
377 safepoints_.Emit(masm(), GetStackSlotCount());
378 return !is_aborted();
379}
380
381
382Register LCodeGen::ToRegister(int index) const {
383 return Register::FromAllocationIndex(index);
384}
385
386
387DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
388 return DoubleRegister::FromAllocationIndex(index);
389}
390
391
392Register LCodeGen::ToRegister(LOperand* op) const {
393 ASSERT(op->IsRegister());
394 return ToRegister(op->index());
395}
396
397
398Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
399 if (op->IsRegister()) {
400 return ToRegister(op->index());
401 } else if (op->IsConstantOperand()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000402 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000403 HConstant* constant = chunk_->LookupConstant(const_op);
404 Handle<Object> literal = constant->handle();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000405 Representation r = chunk_->LookupLiteralRepresentation(const_op);
406 if (r.IsInteger32()) {
407 ASSERT(literal->IsNumber());
408 __ li(scratch, Operand(static_cast<int32_t>(literal->Number())));
409 } else if (r.IsDouble()) {
410 Abort("EmitLoadRegister: Unsupported double immediate.");
411 } else {
412 ASSERT(r.IsTagged());
413 if (literal->IsSmi()) {
414 __ li(scratch, Operand(literal));
415 } else {
416 __ LoadHeapObject(scratch, Handle<HeapObject>::cast(literal));
417 }
418 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000419 return scratch;
420 } else if (op->IsStackSlot() || op->IsArgument()) {
421 __ lw(scratch, ToMemOperand(op));
422 return scratch;
423 }
424 UNREACHABLE();
425 return scratch;
426}
427
428
429DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
430 ASSERT(op->IsDoubleRegister());
431 return ToDoubleRegister(op->index());
432}
433
434
435DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
436 FloatRegister flt_scratch,
437 DoubleRegister dbl_scratch) {
438 if (op->IsDoubleRegister()) {
439 return ToDoubleRegister(op->index());
440 } else if (op->IsConstantOperand()) {
441 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000442 HConstant* constant = chunk_->LookupConstant(const_op);
443 Handle<Object> literal = constant->handle();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000444 Representation r = chunk_->LookupLiteralRepresentation(const_op);
445 if (r.IsInteger32()) {
446 ASSERT(literal->IsNumber());
447 __ li(at, Operand(static_cast<int32_t>(literal->Number())));
448 __ mtc1(at, flt_scratch);
449 __ cvt_d_w(dbl_scratch, flt_scratch);
450 return dbl_scratch;
451 } else if (r.IsDouble()) {
452 Abort("unsupported double immediate");
453 } else if (r.IsTagged()) {
454 Abort("unsupported tagged immediate");
455 }
456 } else if (op->IsStackSlot() || op->IsArgument()) {
457 MemOperand mem_op = ToMemOperand(op);
458 __ ldc1(dbl_scratch, mem_op);
459 return dbl_scratch;
460 }
461 UNREACHABLE();
462 return dbl_scratch;
463}
464
465
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000466Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000467 HConstant* constant = chunk_->LookupConstant(op);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000468 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000469 return constant->handle();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000470}
471
472
473bool LCodeGen::IsInteger32(LConstantOperand* op) const {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +0000474 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000475}
476
477
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +0000478bool LCodeGen::IsSmi(LConstantOperand* op) const {
479 return chunk_->LookupLiteralRepresentation(op).IsSmi();
480}
481
482
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000483int LCodeGen::ToInteger32(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000484 HConstant* constant = chunk_->LookupConstant(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000485 return constant->Integer32Value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000486}
487
488
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000489Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
490 HConstant* constant = chunk_->LookupConstant(op);
491 return Smi::FromInt(constant->Integer32Value());
492}
493
494
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000495double LCodeGen::ToDouble(LConstantOperand* op) const {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000496 HConstant* constant = chunk_->LookupConstant(op);
497 ASSERT(constant->HasDoubleValue());
498 return constant->DoubleValue();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000499}
500
501
502Operand LCodeGen::ToOperand(LOperand* op) {
503 if (op->IsConstantOperand()) {
504 LConstantOperand* const_op = LConstantOperand::cast(op);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000505 HConstant* constant = chunk()->LookupConstant(const_op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000506 Representation r = chunk_->LookupLiteralRepresentation(const_op);
507 if (r.IsInteger32()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000508 ASSERT(constant->HasInteger32Value());
509 return Operand(constant->Integer32Value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000510 } else if (r.IsDouble()) {
511 Abort("ToOperand Unsupported double immediate.");
512 }
513 ASSERT(r.IsTagged());
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000514 return Operand(constant->handle());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000515 } else if (op->IsRegister()) {
516 return Operand(ToRegister(op));
517 } else if (op->IsDoubleRegister()) {
518 Abort("ToOperand IsDoubleRegister unimplemented");
519 return Operand(0);
520 }
521 // Stack slots not implemented, use ToMemOperand instead.
522 UNREACHABLE();
523 return Operand(0);
524}
525
526
527MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
528 ASSERT(!op->IsRegister());
529 ASSERT(!op->IsDoubleRegister());
530 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000531 return MemOperand(fp, StackSlotOffset(op->index()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000532}
533
534
535MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
536 ASSERT(op->IsDoubleStackSlot());
jkummerow@chromium.orgac360712013-02-11 09:00:07 +0000537 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000538}
539
540
541void LCodeGen::WriteTranslation(LEnvironment* environment,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000542 Translation* translation) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000543 if (environment == NULL) return;
544
545 // The translation includes one command per value in the environment.
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000546 int translation_size = environment->translation_size();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000547 // The output frame height does not include the parameters.
548 int height = translation_size - environment->parameter_count();
549
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000550 WriteTranslation(environment->outer(), translation);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000551 bool has_closure_id = !info()->closure().is_null() &&
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000552 !info()->closure().is_identical_to(environment->closure());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000553 int closure_id = has_closure_id
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000554 ? DefineDeoptimizationLiteral(environment->closure())
555 : Translation::kSelfLiteralId;
556
ulan@chromium.org812308e2012-02-29 15:58:45 +0000557 switch (environment->frame_type()) {
558 case JS_FUNCTION:
559 translation->BeginJSFrame(environment->ast_id(), closure_id, height);
560 break;
561 case JS_CONSTRUCT:
562 translation->BeginConstructStubFrame(closure_id, translation_size);
563 break;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000564 case JS_GETTER:
565 ASSERT(translation_size == 1);
566 ASSERT(height == 0);
567 translation->BeginGetterStubFrame(closure_id);
568 break;
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000569 case JS_SETTER:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000570 ASSERT(translation_size == 2);
571 ASSERT(height == 0);
572 translation->BeginSetterStubFrame(closure_id);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000573 break;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000574 case STUB:
575 translation->BeginCompiledStubFrame();
576 break;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000577 case ARGUMENTS_ADAPTOR:
578 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
579 break;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000580 }
ulan@chromium.org56c14af2012-09-20 12:51:09 +0000581
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000582 for (int i = 0; i < translation_size; ++i) {
583 LOperand* value = environment->values()->at(i);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000584
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000585 // TODO(mstarzinger): Introduce marker operands to indicate that this value
586 // is not present and must be reconstructed from the deoptimizer. Currently
587 // this is only used for the arguments object.
588 if (value == NULL) {
589 int arguments_count = environment->values()->length() - translation_size;
590 translation->BeginArgumentsObject(arguments_count);
591 for (int i = 0; i < arguments_count; ++i) {
592 LOperand* value = environment->values()->at(translation_size + i);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000593 AddToTranslation(translation,
594 value,
595 environment->HasTaggedValueAt(translation_size + i),
596 environment->HasUint32ValueAt(translation_size + i));
597 }
598 continue;
599 }
600
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000601 AddToTranslation(translation,
602 value,
603 environment->HasTaggedValueAt(i),
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000604 environment->HasUint32ValueAt(i));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000605 }
606}
607
608
609void LCodeGen::AddToTranslation(Translation* translation,
610 LOperand* op,
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000611 bool is_tagged,
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000612 bool is_uint32) {
613 if (op->IsStackSlot()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614 if (is_tagged) {
615 translation->StoreStackSlot(op->index());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000616 } else if (is_uint32) {
617 translation->StoreUint32StackSlot(op->index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000618 } else {
619 translation->StoreInt32StackSlot(op->index());
620 }
621 } else if (op->IsDoubleStackSlot()) {
622 translation->StoreDoubleStackSlot(op->index());
623 } else if (op->IsArgument()) {
624 ASSERT(is_tagged);
625 int src_index = GetStackSlotCount() + op->index();
626 translation->StoreStackSlot(src_index);
627 } else if (op->IsRegister()) {
628 Register reg = ToRegister(op);
629 if (is_tagged) {
630 translation->StoreRegister(reg);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000631 } else if (is_uint32) {
632 translation->StoreUint32Register(reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000633 } else {
634 translation->StoreInt32Register(reg);
635 }
636 } else if (op->IsDoubleRegister()) {
637 DoubleRegister reg = ToDoubleRegister(op);
638 translation->StoreDoubleRegister(reg);
639 } else if (op->IsConstantOperand()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000640 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
641 int src_index = DefineDeoptimizationLiteral(constant->handle());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000642 translation->StoreLiteral(src_index);
643 } else {
644 UNREACHABLE();
645 }
646}
647
648
649void LCodeGen::CallCode(Handle<Code> code,
650 RelocInfo::Mode mode,
651 LInstruction* instr) {
652 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
653}
654
655
656void LCodeGen::CallCodeGeneric(Handle<Code> code,
657 RelocInfo::Mode mode,
658 LInstruction* instr,
659 SafepointMode safepoint_mode) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000660 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000661 ASSERT(instr != NULL);
662 LPointerMap* pointers = instr->pointer_map();
663 RecordPosition(pointers->position());
664 __ Call(code, mode);
erikcorry0ad885c2011-11-21 13:51:57 +0000665 RecordSafepointWithLazyDeopt(instr, safepoint_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000666}
667
668
669void LCodeGen::CallRuntime(const Runtime::Function* function,
670 int num_arguments,
671 LInstruction* instr) {
672 ASSERT(instr != NULL);
673 LPointerMap* pointers = instr->pointer_map();
674 ASSERT(pointers != NULL);
675 RecordPosition(pointers->position());
676
677 __ CallRuntime(function, num_arguments);
erikcorry0ad885c2011-11-21 13:51:57 +0000678 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000679}
680
681
682void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
683 int argc,
684 LInstruction* instr) {
685 __ CallRuntimeSaveDoubles(id);
686 RecordSafepointWithRegisters(
erikcorry0ad885c2011-11-21 13:51:57 +0000687 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688}
689
690
erikcorry0ad885c2011-11-21 13:51:57 +0000691void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
692 Safepoint::DeoptMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 if (!environment->HasBeenRegistered()) {
694 // Physical stack frame layout:
695 // -x ............. -4 0 ..................................... y
696 // [incoming arguments] [spill slots] [pushed outgoing arguments]
697
698 // Layout of the environment:
699 // 0 ..................................................... size-1
700 // [parameters] [locals] [expression stack including arguments]
701
702 // Layout of the translation:
703 // 0 ........................................................ size - 1 + 4
704 // [expression stack including arguments] [locals] [4 words] [parameters]
705 // |>------------ translation_size ------------<|
706
707 int frame_count = 0;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000708 int jsframe_count = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000709 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
710 ++frame_count;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000711 if (e->frame_type() == JS_FUNCTION) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000712 ++jsframe_count;
713 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000714 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000715 Translation translation(&translations_, frame_count, jsframe_count, zone());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000716 WriteTranslation(environment, &translation);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000717 int deoptimization_index = deoptimizations_.length();
erikcorry0ad885c2011-11-21 13:51:57 +0000718 int pc_offset = masm()->pc_offset();
719 environment->Register(deoptimization_index,
720 translation.index(),
721 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000722 deoptimizations_.Add(environment, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000723 }
724}
725
726
727void LCodeGen::DeoptimizeIf(Condition cc,
728 LEnvironment* environment,
palfia@homejinni.com04109732013-05-15 09:50:32 +0000729 Deoptimizer::BailoutType bailout_type,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000730 Register src1,
731 const Operand& src2) {
erikcorry0ad885c2011-11-21 13:51:57 +0000732 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000733 ASSERT(environment->HasBeenRegistered());
734 int id = environment->deoptimization_index();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000735 ASSERT(info()->IsOptimizing() || info()->IsStub());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000736 Address entry =
737 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000738 if (entry == NULL) {
739 Abort("bailout was not prepared");
740 return;
741 }
742
743 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS.
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000744 if (FLAG_deopt_every_n_times == 1 &&
745 !info()->IsStub() &&
746 info()->opt_count() == id) {
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000747 ASSERT(frame_is_built_);
748 __ Call(entry, RelocInfo::RUNTIME_ENTRY);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000749 return;
750 }
751
jkummerow@chromium.orgfee992b2013-06-19 18:17:45 +0000752 if (FLAG_trap_on_deopt && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000753 Label skip;
754 if (cc != al) {
755 __ Branch(&skip, NegateCondition(cc), src1, src2);
756 }
757 __ stop("trap_on_deopt");
758 __ bind(&skip);
759 }
760
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000761 ASSERT(info()->IsStub() || frame_is_built_);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000762 if (cc == al && frame_is_built_) {
danno@chromium.org169691d2013-07-15 08:01:13 +0000763 __ Call(entry, RelocInfo::RUNTIME_ENTRY, cc, src1, src2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000764 } else {
765 // We often have several deopts to the same entry, reuse the last
766 // jump entry if this is the case.
767 if (deopt_jump_table_.is_empty() ||
768 (deopt_jump_table_.last().address != entry) ||
palfia@homejinni.com04109732013-05-15 09:50:32 +0000769 (deopt_jump_table_.last().bailout_type != bailout_type) ||
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000770 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
palfia@homejinni.com04109732013-05-15 09:50:32 +0000771 Deoptimizer::JumpTableEntry table_entry(entry,
772 bailout_type,
773 !frame_is_built_);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000774 deopt_jump_table_.Add(table_entry, zone());
775 }
776 __ Branch(&deopt_jump_table_.last().label, cc, src1, src2);
777 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000778}
779
780
palfia@homejinni.com04109732013-05-15 09:50:32 +0000781void LCodeGen::DeoptimizeIf(Condition cc,
782 LEnvironment* environment,
783 Register src1,
784 const Operand& src2) {
785 Deoptimizer::BailoutType bailout_type = info()->IsStub()
786 ? Deoptimizer::LAZY
787 : Deoptimizer::EAGER;
788 DeoptimizeIf(cc, environment, bailout_type, src1, src2);
789}
790
791
792void LCodeGen::SoftDeoptimize(LEnvironment* environment,
793 Register src1,
794 const Operand& src2) {
795 ASSERT(!info()->IsStub());
796 DeoptimizeIf(al, environment, Deoptimizer::SOFT, src1, src2);
797}
798
799
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000800void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) {
801 ZoneList<Handle<Map> > maps(1, zone());
802 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
803 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
804 RelocInfo::Mode mode = it.rinfo()->rmode();
805 if (mode == RelocInfo::EMBEDDED_OBJECT &&
806 it.rinfo()->target_object()->IsMap()) {
807 Handle<Map> map(Map::cast(it.rinfo()->target_object()));
808 if (map->CanTransition()) {
809 maps.Add(map, zone());
810 }
811 }
812 }
813#ifdef VERIFY_HEAP
814 // This disables verification of weak embedded maps after full GC.
815 // AddDependentCode can cause a GC, which would observe the state where
816 // this code is not yet in the depended code lists of the embedded maps.
817 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps;
818#endif
819 for (int i = 0; i < maps.length(); i++) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000820 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code);
ulan@chromium.org6ba1fd02013-02-14 14:56:11 +0000821 }
822}
823
824
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
826 int length = deoptimizations_.length();
827 if (length == 0) return;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000828 Handle<DeoptimizationInputData> data =
829 factory()->NewDeoptimizationInputData(length, TENURED);
830
svenpanne@chromium.org876cca82013-03-18 14:43:20 +0000831 Handle<ByteArray> translations =
832 translations_.CreateByteArray(isolate()->factory());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000833 data->SetTranslationByteArray(*translations);
834 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
835
836 Handle<FixedArray> literals =
837 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000838 { AllowDeferredHandleDereference copy_handles;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000839 for (int i = 0; i < deoptimization_literals_.length(); i++) {
840 literals->set(i, *deoptimization_literals_[i]);
841 }
842 data->SetLiteralArray(*literals);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000843 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000844
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000845 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000846 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
847
848 // Populate the deoptimization entries.
849 for (int i = 0; i < length; i++) {
850 LEnvironment* env = deoptimizations_[i];
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000851 data->SetAstId(i, env->ast_id());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000852 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
853 data->SetArgumentsStackHeight(i,
854 Smi::FromInt(env->arguments_stack_height()));
erikcorry0ad885c2011-11-21 13:51:57 +0000855 data->SetPc(i, Smi::FromInt(env->pc_offset()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000856 }
857 code->set_deoptimization_data(*data);
858}
859
860
861int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
862 int result = deoptimization_literals_.length();
863 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
864 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
865 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000866 deoptimization_literals_.Add(literal, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000867 return result;
868}
869
870
871void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
872 ASSERT(deoptimization_literals_.length() == 0);
873
874 const ZoneList<Handle<JSFunction> >* inlined_closures =
875 chunk()->inlined_closures();
876
877 for (int i = 0, length = inlined_closures->length();
878 i < length;
879 i++) {
880 DefineDeoptimizationLiteral(inlined_closures->at(i));
881 }
882
883 inlined_function_count_ = deoptimization_literals_.length();
884}
885
886
erikcorry0ad885c2011-11-21 13:51:57 +0000887void LCodeGen::RecordSafepointWithLazyDeopt(
888 LInstruction* instr, SafepointMode safepoint_mode) {
889 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
890 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
891 } else {
892 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
893 RecordSafepointWithRegisters(
894 instr->pointer_map(), 0, Safepoint::kLazyDeopt);
895 }
896}
897
898
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000899void LCodeGen::RecordSafepoint(
900 LPointerMap* pointers,
901 Safepoint::Kind kind,
902 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000903 Safepoint::DeoptMode deopt_mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000904 ASSERT(expected_safepoint_kind_ == kind);
905
906 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
907 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
erikcorry0ad885c2011-11-21 13:51:57 +0000908 kind, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000909 for (int i = 0; i < operands->length(); i++) {
910 LOperand* pointer = operands->at(i);
911 if (pointer->IsStackSlot()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000912 safepoint.DefinePointerSlot(pointer->index(), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000913 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000914 safepoint.DefinePointerRegister(ToRegister(pointer), zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000915 }
916 }
917 if (kind & Safepoint::kWithRegisters) {
918 // Register cp always contains a pointer to the context.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000919 safepoint.DefinePointerRegister(cp, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000920 }
921}
922
923
924void LCodeGen::RecordSafepoint(LPointerMap* pointers,
erikcorry0ad885c2011-11-21 13:51:57 +0000925 Safepoint::DeoptMode deopt_mode) {
926 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000927}
928
929
erikcorry0ad885c2011-11-21 13:51:57 +0000930void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000931 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
erikcorry0ad885c2011-11-21 13:51:57 +0000932 RecordSafepoint(&empty_pointers, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000933}
934
935
936void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
937 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000938 Safepoint::DeoptMode deopt_mode) {
939 RecordSafepoint(
940 pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000941}
942
943
944void LCodeGen::RecordSafepointWithRegistersAndDoubles(
945 LPointerMap* pointers,
946 int arguments,
erikcorry0ad885c2011-11-21 13:51:57 +0000947 Safepoint::DeoptMode deopt_mode) {
948 RecordSafepoint(
949 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000950}
951
952
953void LCodeGen::RecordPosition(int position) {
954 if (position == RelocInfo::kNoPosition) return;
955 masm()->positions_recorder()->RecordPosition(position);
956}
957
958
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000959static const char* LabelType(LLabel* label) {
960 if (label->is_loop_header()) return " (loop header)";
961 if (label->is_osr_entry()) return " (OSR entry)";
962 return "";
963}
964
965
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000966void LCodeGen::DoLabel(LLabel* label) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000967 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
968 current_instruction_,
969 label->hydrogen_value()->id(),
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +0000970 label->block_id(),
ulan@chromium.org32d7dba2013-04-24 10:59:06 +0000971 LabelType(label));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000972 __ bind(label->label());
973 current_block_ = label->block_id();
974 DoGap(label);
975}
976
977
978void LCodeGen::DoParallelMove(LParallelMove* move) {
979 resolver_.Resolve(move);
980}
981
982
983void LCodeGen::DoGap(LGap* gap) {
984 for (int i = LGap::FIRST_INNER_POSITION;
985 i <= LGap::LAST_INNER_POSITION;
986 i++) {
987 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
988 LParallelMove* move = gap->GetParallelMove(inner_pos);
989 if (move != NULL) DoParallelMove(move);
990 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000991}
992
993
994void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
995 DoGap(instr);
996}
997
998
999void LCodeGen::DoParameter(LParameter* instr) {
1000 // Nothing to do.
1001}
1002
1003
1004void LCodeGen::DoCallStub(LCallStub* instr) {
1005 ASSERT(ToRegister(instr->result()).is(v0));
1006 switch (instr->hydrogen()->major_key()) {
1007 case CodeStub::RegExpConstructResult: {
1008 RegExpConstructResultStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001009 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001010 break;
1011 }
1012 case CodeStub::RegExpExec: {
1013 RegExpExecStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001014 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001015 break;
1016 }
1017 case CodeStub::SubString: {
1018 SubStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001019 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001020 break;
1021 }
1022 case CodeStub::NumberToString: {
1023 NumberToStringStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001024 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001025 break;
1026 }
1027 case CodeStub::StringAdd: {
1028 StringAddStub stub(NO_STRING_ADD_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001029 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001030 break;
1031 }
1032 case CodeStub::StringCompare: {
1033 StringCompareStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001034 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001035 break;
1036 }
1037 case CodeStub::TranscendentalCache: {
1038 __ lw(a0, MemOperand(sp, 0));
1039 TranscendentalCacheStub stub(instr->transcendental_type(),
1040 TranscendentalCacheStub::TAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001041 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001042 break;
1043 }
1044 default:
1045 UNREACHABLE();
1046 }
1047}
1048
1049
1050void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001051 // Record the address of the first unknown OSR value as the place to enter.
1052 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001053}
1054
1055
1056void LCodeGen::DoModI(LModI* instr) {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001057 HMod* hmod = instr->hydrogen();
1058 HValue* left = hmod->left();
1059 HValue* right = hmod->right();
1060 if (hmod->HasPowerOf2Divisor()) {
1061 const Register scratch = scratch0();
1062 const Register left_reg = ToRegister(instr->left());
1063 ASSERT(!left_reg.is(scratch));
1064 const Register result_reg = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001065
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001066 // Note: The code below even works when right contains kMinInt.
1067 int32_t divisor = Abs(right->GetInteger32Constant());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001068
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001069 __ mov(scratch, left_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001070
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001071 Label left_is_not_negative, done;
1072 if (left->CanBeNegative()) {
1073 __ Branch(USE_DELAY_SLOT, &left_is_not_negative,
1074 ge, left_reg, Operand(zero_reg));
1075 __ subu(result_reg, zero_reg, left_reg);
1076 __ And(result_reg, result_reg, divisor - 1);
1077 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1078 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1079 }
1080 __ Branch(USE_DELAY_SLOT, &done);
1081 __ subu(result_reg, zero_reg, result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001082 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001083
1084 __ bind(&left_is_not_negative);
1085 __ And(result_reg, scratch, divisor - 1);
1086 __ bind(&done);
1087
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001088 } else if (hmod->fixed_right_arg().has_value) {
1089 const Register scratch = scratch0();
1090 const Register left_reg = ToRegister(instr->left());
1091 const Register result_reg = ToRegister(instr->result());
erikcorry0ad885c2011-11-21 13:51:57 +00001092
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001093 Register right_reg = EmitLoadRegister(instr->right(), scratch);
1094
1095 int32_t divisor = hmod->fixed_right_arg().value;
1096 ASSERT(IsPowerOf2(divisor));
1097
1098 // Check if our assumption of a fixed right operand still holds.
1099 DeoptimizeIf(ne, instr->environment(), right_reg, Operand(divisor));
1100
1101 Label left_is_not_negative, done;
1102 if (left->CanBeNegative()) {
1103 __ Branch(USE_DELAY_SLOT, &left_is_not_negative,
1104 ge, left_reg, Operand(zero_reg));
1105 __ subu(result_reg, zero_reg, left_reg);
1106 __ And(result_reg, result_reg, divisor - 1);
1107 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1108 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
1109 }
1110 __ Branch(USE_DELAY_SLOT, &done);
1111 __ subu(result_reg, zero_reg, result_reg);
1112 }
1113
1114 __ bind(&left_is_not_negative);
1115 __ And(result_reg, left_reg, divisor - 1);
1116 __ bind(&done);
1117
1118 } else {
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001119 const Register scratch = scratch0();
1120 const Register left_reg = ToRegister(instr->left());
1121 const Register result_reg = ToRegister(instr->result());
1122
1123 // div runs in the background while we check for special cases.
1124 Register right_reg = EmitLoadRegister(instr->right(), scratch);
1125 __ div(left_reg, right_reg);
1126
1127 Label done;
1128 // Check for x % 0, we have to deopt in this case because we can't return a
1129 // NaN.
1130 if (right->CanBeZero()) {
1131 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001132 }
1133
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001134 // Check for kMinInt % -1, we have to deopt if we care about -0, because we
1135 // can't return that.
1136 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001137 Label left_not_min_int;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001138 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt));
1139 // TODO(svenpanne) Don't deopt when we don't care about -0.
1140 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001141 __ bind(&left_not_min_int);
1142 }
1143
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001144 // TODO(svenpanne) Only emit the test/deopt if we have to.
1145 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg));
1146 __ mfhi(result_reg);
erikcorry0ad885c2011-11-21 13:51:57 +00001147
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001148 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
1149 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg));
erikcorry0ad885c2011-11-21 13:51:57 +00001150 }
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001151 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001152 }
1153}
1154
1155
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001156void LCodeGen::EmitSignedIntegerDivisionByConstant(
1157 Register result,
1158 Register dividend,
1159 int32_t divisor,
1160 Register remainder,
1161 Register scratch,
1162 LEnvironment* environment) {
1163 ASSERT(!AreAliased(dividend, scratch, at, no_reg));
1164 ASSERT(LChunkBuilder::HasMagicNumberForDivisor(divisor));
1165
1166 uint32_t divisor_abs = abs(divisor);
1167
1168 int32_t power_of_2_factor =
1169 CompilerIntrinsics::CountTrailingZeros(divisor_abs);
1170
1171 switch (divisor_abs) {
1172 case 0:
1173 DeoptimizeIf(al, environment);
1174 return;
1175
1176 case 1:
1177 if (divisor > 0) {
1178 __ Move(result, dividend);
1179 } else {
1180 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch);
1181 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg));
1182 }
1183 // Compute the remainder.
1184 __ Move(remainder, zero_reg);
1185 return;
1186
1187 default:
1188 if (IsPowerOf2(divisor_abs)) {
1189 // Branch and condition free code for integer division by a power
1190 // of two.
1191 int32_t power = WhichPowerOf2(divisor_abs);
1192 if (power > 1) {
1193 __ sra(scratch, dividend, power - 1);
1194 }
1195 __ srl(scratch, scratch, 32 - power);
1196 __ Addu(scratch, dividend, Operand(scratch));
1197 __ sra(result, scratch, power);
1198 // Negate if necessary.
1199 // We don't need to check for overflow because the case '-1' is
1200 // handled separately.
1201 if (divisor < 0) {
1202 ASSERT(divisor != -1);
1203 __ Subu(result, zero_reg, Operand(result));
1204 }
1205 // Compute the remainder.
1206 if (divisor > 0) {
1207 __ sll(scratch, result, power);
1208 __ Subu(remainder, dividend, Operand(scratch));
1209 } else {
1210 __ sll(scratch, result, power);
1211 __ Addu(remainder, dividend, Operand(scratch));
1212 }
1213 return;
1214 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) {
1215 // Use magic numbers for a few specific divisors.
1216 // Details and proofs can be found in:
1217 // - Hacker's Delight, Henry S. Warren, Jr.
1218 // - The PowerPC Compiler Writer's Guide
1219 // and probably many others.
1220 //
1221 // We handle
1222 // <divisor with magic numbers> * <power of 2>
1223 // but not
1224 // <divisor with magic numbers> * <other divisor with magic numbers>
1225 DivMagicNumbers magic_numbers =
1226 DivMagicNumberFor(divisor_abs >> power_of_2_factor);
1227 // Branch and condition free code for integer division by a power
1228 // of two.
1229 const int32_t M = magic_numbers.M;
1230 const int32_t s = magic_numbers.s + power_of_2_factor;
1231
1232 __ li(scratch, Operand(M));
1233 __ mult(dividend, scratch);
1234 __ mfhi(scratch);
1235 if (M < 0) {
1236 __ Addu(scratch, scratch, Operand(dividend));
1237 }
1238 if (s > 0) {
1239 __ sra(scratch, scratch, s);
1240 __ mov(scratch, scratch);
1241 }
1242 __ srl(at, dividend, 31);
1243 __ Addu(result, scratch, Operand(at));
1244 if (divisor < 0) __ Subu(result, zero_reg, Operand(result));
1245 // Compute the remainder.
1246 __ li(scratch, Operand(divisor));
1247 __ Mul(scratch, result, Operand(scratch));
1248 __ Subu(remainder, dividend, Operand(scratch));
1249 } else {
1250 __ li(scratch, Operand(divisor));
1251 __ div(dividend, scratch);
1252 __ mfhi(remainder);
1253 __ mflo(result);
1254 }
1255 }
1256}
1257
1258
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001259void LCodeGen::DoDivI(LDivI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001260 const Register left = ToRegister(instr->left());
1261 const Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001262 const Register result = ToRegister(instr->result());
1263
1264 // On MIPS div is asynchronous - it will run in the background while we
1265 // check for special cases.
1266 __ div(left, right);
1267
1268 // Check for x / 0.
1269 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
1270 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1271 }
1272
1273 // Check for (0 / -x) that will produce negative zero.
1274 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1275 Label left_not_zero;
1276 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1277 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1278 __ bind(&left_not_zero);
1279 }
1280
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001281 // Check for (kMinInt / -1).
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001282 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1283 Label left_not_min_int;
1284 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1285 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1286 __ bind(&left_not_min_int);
1287 }
1288
danno@chromium.org41728482013-06-12 22:31:22 +00001289 if (!instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1290 __ mfhi(result);
1291 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg));
1292 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001293 __ mflo(result);
1294}
1295
1296
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001297void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) {
1298 DoubleRegister addend = ToDoubleRegister(instr->addend());
1299 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier());
1300 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand());
1301
1302 // This is computed in-place.
1303 ASSERT(addend.is(ToDoubleRegister(instr->result())));
1304
1305 __ madd_d(addend, addend, multiplier, multiplicand);
1306}
1307
1308
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001309void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
1310 const Register result = ToRegister(instr->result());
1311 const Register left = ToRegister(instr->left());
1312 const Register remainder = ToRegister(instr->temp());
1313 const Register scratch = scratch0();
1314
1315 if (instr->right()->IsConstantOperand()) {
1316 Label done;
1317 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right()));
1318 if (divisor < 0) {
1319 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1320 }
1321 EmitSignedIntegerDivisionByConstant(result,
1322 left,
1323 divisor,
1324 remainder,
1325 scratch,
1326 instr->environment());
1327 // We performed a truncating division. Correct the result if necessary.
1328 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1329 __ Xor(scratch , remainder, Operand(divisor));
1330 __ Branch(&done, ge, scratch, Operand(zero_reg));
1331 __ Subu(result, result, Operand(1));
1332 __ bind(&done);
1333 } else {
1334 Label done;
1335 const Register right = ToRegister(instr->right());
1336
1337 // On MIPS div is asynchronous - it will run in the background while we
1338 // check for special cases.
1339 __ div(left, right);
1340
1341 // Check for x / 0.
1342 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg));
1343
1344 // Check for (0 / -x) that will produce negative zero.
1345 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1346 Label left_not_zero;
1347 __ Branch(&left_not_zero, ne, left, Operand(zero_reg));
1348 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg));
1349 __ bind(&left_not_zero);
1350 }
1351
1352 // Check for (kMinInt / -1).
1353 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1354 Label left_not_min_int;
1355 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt));
1356 DeoptimizeIf(eq, instr->environment(), right, Operand(-1));
1357 __ bind(&left_not_min_int);
1358 }
1359
1360 __ mfhi(remainder);
1361 __ mflo(result);
1362
1363 // We performed a truncating division. Correct the result if necessary.
1364 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT);
1365 __ Xor(scratch , remainder, Operand(right));
1366 __ Branch(&done, ge, scratch, Operand(zero_reg));
1367 __ Subu(result, result, Operand(1));
1368 __ bind(&done);
1369 }
1370}
1371
1372
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001373void LCodeGen::DoMulI(LMulI* instr) {
1374 Register scratch = scratch0();
1375 Register result = ToRegister(instr->result());
1376 // Note that result may alias left.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001377 Register left = ToRegister(instr->left());
1378 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001379
1380 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1381 bool bailout_on_minus_zero =
1382 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
1383
1384 if (right_op->IsConstantOperand() && !can_overflow) {
1385 // Use optimized code for specific constants.
1386 int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
1387
1388 if (bailout_on_minus_zero && (constant < 0)) {
1389 // The case of a null constant will be handled separately.
1390 // If constant is negative and left is null, the result should be -0.
1391 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg));
1392 }
1393
1394 switch (constant) {
1395 case -1:
1396 __ Subu(result, zero_reg, left);
1397 break;
1398 case 0:
1399 if (bailout_on_minus_zero) {
1400 // If left is strictly negative and the constant is null, the
1401 // result is -0. Deoptimize if required, otherwise return 0.
1402 DeoptimizeIf(lt, instr->environment(), left, Operand(zero_reg));
1403 }
1404 __ mov(result, zero_reg);
1405 break;
1406 case 1:
1407 // Nothing to do.
1408 __ Move(result, left);
1409 break;
1410 default:
1411 // Multiplying by powers of two and powers of two plus or minus
1412 // one can be done faster with shifted operands.
1413 // For other constants we emit standard code.
1414 int32_t mask = constant >> 31;
1415 uint32_t constant_abs = (constant + mask) ^ mask;
1416
1417 if (IsPowerOf2(constant_abs) ||
1418 IsPowerOf2(constant_abs - 1) ||
1419 IsPowerOf2(constant_abs + 1)) {
1420 if (IsPowerOf2(constant_abs)) {
1421 int32_t shift = WhichPowerOf2(constant_abs);
1422 __ sll(result, left, shift);
1423 } else if (IsPowerOf2(constant_abs - 1)) {
1424 int32_t shift = WhichPowerOf2(constant_abs - 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001425 __ sll(scratch, left, shift);
1426 __ Addu(result, scratch, left);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001427 } else if (IsPowerOf2(constant_abs + 1)) {
1428 int32_t shift = WhichPowerOf2(constant_abs + 1);
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001429 __ sll(scratch, left, shift);
1430 __ Subu(result, scratch, left);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001431 }
1432
1433 // Correct the sign of the result is the constant is negative.
1434 if (constant < 0) {
1435 __ Subu(result, zero_reg, result);
1436 }
1437
1438 } else {
1439 // Generate standard code.
1440 __ li(at, constant);
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001441 __ Mul(result, left, at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001442 }
1443 }
1444
1445 } else {
1446 Register right = EmitLoadRegister(right_op, scratch);
1447 if (bailout_on_minus_zero) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001448 __ Or(ToRegister(instr->temp()), left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001449 }
1450
1451 if (can_overflow) {
1452 // hi:lo = left * right.
1453 __ mult(left, right);
1454 __ mfhi(scratch);
1455 __ mflo(result);
1456 __ sra(at, result, 31);
1457 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
1458 } else {
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +00001459 __ Mul(result, left, right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001460 }
1461
1462 if (bailout_on_minus_zero) {
1463 // Bail out if the result is supposed to be negative zero.
1464 Label done;
1465 __ Branch(&done, ne, result, Operand(zero_reg));
1466 DeoptimizeIf(lt,
1467 instr->environment(),
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001468 ToRegister(instr->temp()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001469 Operand(zero_reg));
1470 __ bind(&done);
1471 }
1472 }
1473}
1474
1475
1476void LCodeGen::DoBitI(LBitI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001477 LOperand* left_op = instr->left();
1478 LOperand* right_op = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001479 ASSERT(left_op->IsRegister());
1480 Register left = ToRegister(left_op);
1481 Register result = ToRegister(instr->result());
1482 Operand right(no_reg);
1483
1484 if (right_op->IsStackSlot() || right_op->IsArgument()) {
1485 right = Operand(EmitLoadRegister(right_op, at));
1486 } else {
1487 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
1488 right = ToOperand(right_op);
1489 }
1490
1491 switch (instr->op()) {
1492 case Token::BIT_AND:
1493 __ And(result, left, right);
1494 break;
1495 case Token::BIT_OR:
1496 __ Or(result, left, right);
1497 break;
1498 case Token::BIT_XOR:
1499 __ Xor(result, left, right);
1500 break;
1501 default:
1502 UNREACHABLE();
1503 break;
1504 }
1505}
1506
1507
1508void LCodeGen::DoShiftI(LShiftI* instr) {
1509 // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
1510 // result may alias either of them.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001511 LOperand* right_op = instr->right();
1512 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001513 Register result = ToRegister(instr->result());
1514
1515 if (right_op->IsRegister()) {
1516 // No need to mask the right operand on MIPS, it is built into the variable
1517 // shift instructions.
1518 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001519 case Token::ROR:
1520 __ Ror(result, left, Operand(ToRegister(right_op)));
1521 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001522 case Token::SAR:
1523 __ srav(result, left, ToRegister(right_op));
1524 break;
1525 case Token::SHR:
1526 __ srlv(result, left, ToRegister(right_op));
1527 if (instr->can_deopt()) {
1528 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
1529 }
1530 break;
1531 case Token::SHL:
1532 __ sllv(result, left, ToRegister(right_op));
1533 break;
1534 default:
1535 UNREACHABLE();
1536 break;
1537 }
1538 } else {
1539 // Mask the right_op operand.
1540 int value = ToInteger32(LConstantOperand::cast(right_op));
1541 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1542 switch (instr->op()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001543 case Token::ROR:
1544 if (shift_count != 0) {
1545 __ Ror(result, left, Operand(shift_count));
1546 } else {
1547 __ Move(result, left);
1548 }
1549 break;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001550 case Token::SAR:
1551 if (shift_count != 0) {
1552 __ sra(result, left, shift_count);
1553 } else {
1554 __ Move(result, left);
1555 }
1556 break;
1557 case Token::SHR:
1558 if (shift_count != 0) {
1559 __ srl(result, left, shift_count);
1560 } else {
1561 if (instr->can_deopt()) {
1562 __ And(at, left, Operand(0x80000000));
1563 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
1564 }
1565 __ Move(result, left);
1566 }
1567 break;
1568 case Token::SHL:
1569 if (shift_count != 0) {
1570 __ sll(result, left, shift_count);
1571 } else {
1572 __ Move(result, left);
1573 }
1574 break;
1575 default:
1576 UNREACHABLE();
1577 break;
1578 }
1579 }
1580}
1581
1582
1583void LCodeGen::DoSubI(LSubI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001584 LOperand* left = instr->left();
1585 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001586 LOperand* result = instr->result();
1587 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1588
1589 if (!can_overflow) {
1590 if (right->IsStackSlot() || right->IsArgument()) {
1591 Register right_reg = EmitLoadRegister(right, at);
1592 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg));
1593 } else {
1594 ASSERT(right->IsRegister() || right->IsConstantOperand());
1595 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
1596 }
1597 } else { // can_overflow.
1598 Register overflow = scratch0();
1599 Register scratch = scratch1();
1600 if (right->IsStackSlot() ||
1601 right->IsArgument() ||
1602 right->IsConstantOperand()) {
1603 Register right_reg = EmitLoadRegister(right, scratch);
1604 __ SubuAndCheckForOverflow(ToRegister(result),
1605 ToRegister(left),
1606 right_reg,
1607 overflow); // Reg at also used as scratch.
1608 } else {
1609 ASSERT(right->IsRegister());
1610 // Due to overflow check macros not supporting constant operands,
1611 // handling the IsConstantOperand case was moved to prev if clause.
1612 __ SubuAndCheckForOverflow(ToRegister(result),
1613 ToRegister(left),
1614 ToRegister(right),
1615 overflow); // Reg at also used as scratch.
1616 }
1617 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1618 }
1619}
1620
1621
1622void LCodeGen::DoConstantI(LConstantI* instr) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00001623 __ li(ToRegister(instr->result()), Operand(instr->value()));
1624}
1625
1626
1627void LCodeGen::DoConstantS(LConstantS* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001628 __ li(ToRegister(instr->result()), Operand(instr->value()));
1629}
1630
1631
1632void LCodeGen::DoConstantD(LConstantD* instr) {
1633 ASSERT(instr->result()->IsDoubleRegister());
1634 DoubleRegister result = ToDoubleRegister(instr->result());
1635 double v = instr->value();
1636 __ Move(result, v);
1637}
1638
1639
1640void LCodeGen::DoConstantT(LConstantT* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001641 Handle<Object> value = instr->value();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001642 AllowDeferredHandleDereference smi_check;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001643 if (value->IsSmi()) {
1644 __ li(ToRegister(instr->result()), Operand(value));
1645 } else {
1646 __ LoadHeapObject(ToRegister(instr->result()),
1647 Handle<HeapObject>::cast(value));
1648 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001649}
1650
1651
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001652void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
1653 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001654 Register map = ToRegister(instr->value());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001655 __ EnumLength(result, map);
1656}
1657
1658
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001659void LCodeGen::DoElementsKind(LElementsKind* instr) {
1660 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001661 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001662
1663 // Load map into |result|.
1664 __ lw(result, FieldMemOperand(input, HeapObject::kMapOffset));
1665 // Load the map's "bit field 2" into |result|. We only need the first byte,
1666 // but the following bit field extraction takes care of that anyway.
1667 __ lbu(result, FieldMemOperand(result, Map::kBitField2Offset));
1668 // Retrieve elements_kind from bit field 2.
1669 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
1670}
1671
1672
1673void LCodeGen::DoValueOf(LValueOf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001674 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001675 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001676 Register map = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001677 Label done;
1678
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001679 if (!instr->hydrogen()->value()->IsHeapObject()) {
1680 // If the object is a smi return the object.
1681 __ Move(result, input);
1682 __ JumpIfSmi(input, &done);
1683 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001684
1685 // If the object is not a value type, return the object.
1686 __ GetObjectType(input, map, map);
1687 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE));
1688 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset));
1689
1690 __ bind(&done);
1691}
1692
1693
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001694void LCodeGen::DoDateField(LDateField* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001695 Register object = ToRegister(instr->date());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001696 Register result = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001697 Register scratch = ToRegister(instr->temp());
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001698 Smi* index = instr->index();
1699 Label runtime, done;
1700 ASSERT(object.is(a0));
1701 ASSERT(result.is(v0));
1702 ASSERT(!scratch.is(scratch0()));
1703 ASSERT(!scratch.is(object));
1704
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001705 __ And(at, object, Operand(kSmiTagMask));
1706 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001707 __ GetObjectType(object, scratch, scratch);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001708 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE));
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001709
1710 if (index->value() == 0) {
1711 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
1712 } else {
1713 if (index->value() < JSDate::kFirstUncachedField) {
1714 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
1715 __ li(scratch, Operand(stamp));
1716 __ lw(scratch, MemOperand(scratch));
1717 __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
1718 __ Branch(&runtime, ne, scratch, Operand(scratch0()));
1719 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
1720 kPointerSize * index->value()));
1721 __ jmp(&done);
1722 }
1723 __ bind(&runtime);
1724 __ PrepareCallCFunction(2, scratch);
1725 __ li(a1, Operand(index));
1726 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
1727 __ bind(&done);
1728 }
1729}
1730
1731
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001732void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00001733 Register string = ToRegister(instr->string());
1734 Register index = ToRegister(instr->index());
1735 Register value = ToRegister(instr->value());
1736 Register scratch = scratch0();
1737 String::Encoding encoding = instr->encoding();
1738
1739 if (FLAG_debug_code) {
1740 __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset));
1741 __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
1742
1743 __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask));
1744 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
1745 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
1746 __ Subu(at, at, Operand(encoding == String::ONE_BYTE_ENCODING
1747 ? one_byte_seq_type : two_byte_seq_type));
1748 __ Check(eq, "Unexpected string type", at, Operand(zero_reg));
1749 }
1750
1751 __ Addu(scratch,
1752 string,
1753 Operand(SeqString::kHeaderSize - kHeapObjectTag));
1754 if (encoding == String::ONE_BYTE_ENCODING) {
1755 __ Addu(at, scratch, index);
1756 __ sb(value, MemOperand(at));
1757 } else {
1758 __ sll(at, index, 1);
1759 __ Addu(at, scratch, at);
1760 __ sh(value, MemOperand(at));
1761 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001762}
1763
1764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001765void LCodeGen::DoBitNotI(LBitNotI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001766 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001767 Register result = ToRegister(instr->result());
1768 __ Nor(result, zero_reg, Operand(input));
1769}
1770
1771
1772void LCodeGen::DoThrow(LThrow* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001773 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001774 __ push(input_reg);
1775 CallRuntime(Runtime::kThrow, 1, instr);
1776
1777 if (FLAG_debug_code) {
1778 __ stop("Unreachable code.");
1779 }
1780}
1781
1782
1783void LCodeGen::DoAddI(LAddI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001784 LOperand* left = instr->left();
1785 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001786 LOperand* result = instr->result();
1787 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1788
1789 if (!can_overflow) {
1790 if (right->IsStackSlot() || right->IsArgument()) {
1791 Register right_reg = EmitLoadRegister(right, at);
1792 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg));
1793 } else {
1794 ASSERT(right->IsRegister() || right->IsConstantOperand());
1795 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
1796 }
1797 } else { // can_overflow.
1798 Register overflow = scratch0();
1799 Register scratch = scratch1();
1800 if (right->IsStackSlot() ||
1801 right->IsArgument() ||
1802 right->IsConstantOperand()) {
1803 Register right_reg = EmitLoadRegister(right, scratch);
1804 __ AdduAndCheckForOverflow(ToRegister(result),
1805 ToRegister(left),
1806 right_reg,
1807 overflow); // Reg at also used as scratch.
1808 } else {
1809 ASSERT(right->IsRegister());
1810 // Due to overflow check macros not supporting constant operands,
1811 // handling the IsConstantOperand case was moved to prev if clause.
1812 __ AdduAndCheckForOverflow(ToRegister(result),
1813 ToRegister(left),
1814 ToRegister(right),
1815 overflow); // Reg at also used as scratch.
1816 }
1817 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg));
1818 }
1819}
1820
1821
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001822void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001823 LOperand* left = instr->left();
1824 LOperand* right = instr->right();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001825 HMathMinMax::Operation operation = instr->hydrogen()->operation();
1826 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge;
1827 if (instr->hydrogen()->representation().IsInteger32()) {
1828 Register left_reg = ToRegister(left);
1829 Operand right_op = (right->IsRegister() || right->IsConstantOperand())
1830 ? ToOperand(right)
1831 : Operand(EmitLoadRegister(right, at));
1832 Register result_reg = ToRegister(instr->result());
1833 Label return_right, done;
1834 if (!result_reg.is(left_reg)) {
1835 __ Branch(&return_right, NegateCondition(condition), left_reg, right_op);
1836 __ mov(result_reg, left_reg);
1837 __ Branch(&done);
1838 }
1839 __ Branch(&done, condition, left_reg, right_op);
1840 __ bind(&return_right);
1841 __ Addu(result_reg, zero_reg, right_op);
1842 __ bind(&done);
1843 } else {
1844 ASSERT(instr->hydrogen()->representation().IsDouble());
1845 FPURegister left_reg = ToDoubleRegister(left);
1846 FPURegister right_reg = ToDoubleRegister(right);
1847 FPURegister result_reg = ToDoubleRegister(instr->result());
1848 Label check_nan_left, check_zero, return_left, return_right, done;
1849 __ BranchF(&check_zero, &check_nan_left, eq, left_reg, right_reg);
1850 __ BranchF(&return_left, NULL, condition, left_reg, right_reg);
1851 __ Branch(&return_right);
1852
1853 __ bind(&check_zero);
1854 // left == right != 0.
1855 __ BranchF(&return_left, NULL, ne, left_reg, kDoubleRegZero);
1856 // At this point, both left and right are either 0 or -0.
1857 if (operation == HMathMinMax::kMathMin) {
1858 __ neg_d(left_reg, left_reg);
1859 __ sub_d(result_reg, left_reg, right_reg);
1860 __ neg_d(result_reg, result_reg);
1861 } else {
1862 __ add_d(result_reg, left_reg, right_reg);
1863 }
1864 __ Branch(&done);
1865
1866 __ bind(&check_nan_left);
1867 // left == NaN.
1868 __ BranchF(NULL, &return_left, eq, left_reg, left_reg);
1869 __ bind(&return_right);
1870 if (!right_reg.is(result_reg)) {
1871 __ mov_d(result_reg, right_reg);
1872 }
1873 __ Branch(&done);
1874
1875 __ bind(&return_left);
1876 if (!left_reg.is(result_reg)) {
1877 __ mov_d(result_reg, left_reg);
1878 }
1879 __ bind(&done);
1880 }
1881}
1882
1883
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001884void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001885 DoubleRegister left = ToDoubleRegister(instr->left());
1886 DoubleRegister right = ToDoubleRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001887 DoubleRegister result = ToDoubleRegister(instr->result());
1888 switch (instr->op()) {
1889 case Token::ADD:
1890 __ add_d(result, left, right);
1891 break;
1892 case Token::SUB:
1893 __ sub_d(result, left, right);
1894 break;
1895 case Token::MUL:
1896 __ mul_d(result, left, right);
1897 break;
1898 case Token::DIV:
1899 __ div_d(result, left, right);
1900 break;
1901 case Token::MOD: {
1902 // Save a0-a3 on the stack.
1903 RegList saved_regs = a0.bit() | a1.bit() | a2.bit() | a3.bit();
1904 __ MultiPush(saved_regs);
1905
1906 __ PrepareCallCFunction(0, 2, scratch0());
1907 __ SetCallCDoubleArguments(left, right);
1908 __ CallCFunction(
1909 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1910 0, 2);
1911 // Move the result in the double result register.
1912 __ GetCFunctionDoubleResult(result);
1913
1914 // Restore saved register.
1915 __ MultiPop(saved_regs);
1916 break;
1917 }
1918 default:
1919 UNREACHABLE();
1920 break;
1921 }
1922}
1923
1924
1925void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001926 ASSERT(ToRegister(instr->left()).is(a1));
1927 ASSERT(ToRegister(instr->right()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001928 ASSERT(ToRegister(instr->result()).is(v0));
1929
1930 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001931 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001932 // Other arch use a nop here, to signal that there is no inlined
1933 // patchable code. Mips does not need the nop, since our marker
1934 // instruction (andi zero_reg) will never be used in normal code.
1935}
1936
1937
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00001938int LCodeGen::GetNextEmittedBlock() const {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001939 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
1940 if (!chunk_->GetLabel(i)->HasReplacement()) return i;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001941 }
1942 return -1;
1943}
1944
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001945template<class InstrType>
1946void LCodeGen::EmitBranch(InstrType instr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001947 Condition cc, Register src1, const Operand& src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001948 int left_block = instr->TrueDestination(chunk_);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001949 int right_block = instr->FalseDestination(chunk_);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001950
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001951 int next_block = GetNextEmittedBlock();
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001952 if (right_block == left_block || cc == al) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001953 EmitGoto(left_block);
1954 } else if (left_block == next_block) {
1955 __ Branch(chunk_->GetAssemblyLabel(right_block),
1956 NegateCondition(cc), src1, src2);
1957 } else if (right_block == next_block) {
1958 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2);
1959 } else {
1960 __ Branch(chunk_->GetAssemblyLabel(left_block), cc, src1, src2);
1961 __ Branch(chunk_->GetAssemblyLabel(right_block));
1962 }
1963}
1964
1965
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001966template<class InstrType>
1967void LCodeGen::EmitBranchF(InstrType instr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001968 Condition cc, FPURegister src1, FPURegister src2) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001969 int right_block = instr->FalseDestination(chunk_);
1970 int left_block = instr->TrueDestination(chunk_);
1971
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001972 int next_block = GetNextEmittedBlock();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001973 if (right_block == left_block) {
1974 EmitGoto(left_block);
1975 } else if (left_block == next_block) {
1976 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL,
1977 NegateCondition(cc), src1, src2);
1978 } else if (right_block == next_block) {
1979 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2);
1980 } else {
1981 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, cc, src1, src2);
1982 __ Branch(chunk_->GetAssemblyLabel(right_block));
1983 }
1984}
1985
1986
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00001987void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
1988 __ stop("LDebugBreak");
1989}
1990
1991
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001992void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) {
1993 Representation r = instr->hydrogen()->value()->representation();
1994 if (r.IsSmiOrInteger32() || r.IsDouble()) {
1995 EmitBranch(instr, al, zero_reg, Operand(zero_reg));
1996 } else {
1997 ASSERT(r.IsTagged());
1998 Register reg = ToRegister(instr->value());
1999 HType type = instr->hydrogen()->value()->type();
2000 if (type.IsTaggedNumber()) {
2001 EmitBranch(instr, al, zero_reg, Operand(zero_reg));
2002 }
2003 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
2004 __ lw(scratch0(), FieldMemOperand(reg, HeapObject::kMapOffset));
2005 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
2006 EmitBranch(instr, eq, scratch0(), Operand(at));
2007 }
2008}
2009
2010
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002011void LCodeGen::DoBranch(LBranch* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002012 Representation r = instr->hydrogen()->value()->representation();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002013 if (r.IsInteger32() || r.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002014 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002015 Register reg = ToRegister(instr->value());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002016 EmitBranch(instr, ne, reg, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002017 } else if (r.IsDouble()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002018 ASSERT(!info()->IsStub());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002019 DoubleRegister reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002020 // Test the double value. Zero and NaN are false.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002021 EmitBranchF(instr, nue, reg, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002022 } else {
2023 ASSERT(r.IsTagged());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002024 Register reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002025 HType type = instr->hydrogen()->value()->type();
2026 if (type.IsBoolean()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002027 ASSERT(!info()->IsStub());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002028 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002029 EmitBranch(instr, eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002030 } else if (type.IsSmi()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002031 ASSERT(!info()->IsStub());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002032 EmitBranch(instr, ne, reg, Operand(zero_reg));
2033 } else if (type.IsJSArray()) {
2034 ASSERT(!info()->IsStub());
2035 EmitBranch(instr, al, zero_reg, Operand(zero_reg));
2036 } else if (type.IsHeapNumber()) {
2037 ASSERT(!info()->IsStub());
2038 DoubleRegister dbl_scratch = double_scratch0();
2039 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
2040 // Test the double value. Zero and NaN are false.
2041 EmitBranchF(instr, nue, dbl_scratch, kDoubleRegZero);
2042 } else if (type.IsString()) {
2043 ASSERT(!info()->IsStub());
2044 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
2045 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002046 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002047 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
2048 // Avoid deopts in the case where we've never executed this path before.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002049 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002050
2051 if (expected.Contains(ToBooleanStub::UNDEFINED)) {
2052 // undefined -> false.
2053 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002054 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002055 }
2056 if (expected.Contains(ToBooleanStub::BOOLEAN)) {
2057 // Boolean -> its value.
2058 __ LoadRoot(at, Heap::kTrueValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002059 __ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002060 __ LoadRoot(at, Heap::kFalseValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002061 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002062 }
2063 if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
2064 // 'null' -> false.
2065 __ LoadRoot(at, Heap::kNullValueRootIndex);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002066 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002067 }
2068
2069 if (expected.Contains(ToBooleanStub::SMI)) {
2070 // Smis: 0 -> false, all other -> true.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002071 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg));
2072 __ JumpIfSmi(reg, instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002073 } else if (expected.NeedsMap()) {
2074 // If we need a map later and have a Smi -> deopt.
2075 __ And(at, reg, Operand(kSmiTagMask));
2076 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
2077 }
2078
2079 const Register map = scratch0();
2080 if (expected.NeedsMap()) {
2081 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset));
2082 if (expected.CanBeUndetectable()) {
2083 // Undetectable -> false.
2084 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
2085 __ And(at, at, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002086 __ Branch(instr->FalseLabel(chunk_), ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002087 }
2088 }
2089
2090 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
2091 // spec object -> true.
2092 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002093 __ Branch(instr->TrueLabel(chunk_),
2094 ge, at, Operand(FIRST_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002095 }
2096
2097 if (expected.Contains(ToBooleanStub::STRING)) {
2098 // String value -> false iff empty.
2099 Label not_string;
2100 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset));
2101 __ Branch(&not_string, ge , at, Operand(FIRST_NONSTRING_TYPE));
2102 __ lw(at, FieldMemOperand(reg, String::kLengthOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002103 __ Branch(instr->TrueLabel(chunk_), ne, at, Operand(zero_reg));
2104 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002105 __ bind(&not_string);
2106 }
2107
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002108 if (expected.Contains(ToBooleanStub::SYMBOL)) {
2109 // Symbol value -> true.
2110 const Register scratch = scratch1();
2111 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002112 __ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00002113 }
2114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002115 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
2116 // heap number -> false iff +0, -0, or NaN.
2117 DoubleRegister dbl_scratch = double_scratch0();
2118 Label not_heap_number;
2119 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
2120 __ Branch(&not_heap_number, ne, map, Operand(at));
2121 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002122 __ BranchF(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2123 ne, dbl_scratch, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002124 // Falls through if dbl_scratch == 0.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002125 __ Branch(instr->FalseLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002126 __ bind(&not_heap_number);
2127 }
2128
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002129 if (!expected.IsGeneric()) {
2130 // We've seen something for the first time -> deopt.
2131 // This can only happen if we are not generic already.
2132 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
2133 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002134 }
2135 }
2136}
2137
2138
2139void LCodeGen::EmitGoto(int block) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00002140 if (!IsNextEmittedBlock(block)) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002141 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002142 }
2143}
2144
2145
2146void LCodeGen::DoGoto(LGoto* instr) {
2147 EmitGoto(instr->block_id());
2148}
2149
2150
2151Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
2152 Condition cond = kNoCondition;
2153 switch (op) {
2154 case Token::EQ:
2155 case Token::EQ_STRICT:
2156 cond = eq;
2157 break;
2158 case Token::LT:
2159 cond = is_unsigned ? lo : lt;
2160 break;
2161 case Token::GT:
2162 cond = is_unsigned ? hi : gt;
2163 break;
2164 case Token::LTE:
2165 cond = is_unsigned ? ls : le;
2166 break;
2167 case Token::GTE:
2168 cond = is_unsigned ? hs : ge;
2169 break;
2170 case Token::IN:
2171 case Token::INSTANCEOF:
2172 default:
2173 UNREACHABLE();
2174 }
2175 return cond;
2176}
2177
2178
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00002179void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002180 LOperand* left = instr->left();
2181 LOperand* right = instr->right();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002182 Condition cond = TokenToCondition(instr->op(), false);
2183
2184 if (left->IsConstantOperand() && right->IsConstantOperand()) {
2185 // We can statically evaluate the comparison.
2186 double left_val = ToDouble(LConstantOperand::cast(left));
2187 double right_val = ToDouble(LConstantOperand::cast(right));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002188 int next_block = EvalComparison(instr->op(), left_val, right_val) ?
2189 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002190 EmitGoto(next_block);
2191 } else {
2192 if (instr->is_double()) {
2193 // Compare left and right as doubles and load the
2194 // resulting flags into the normal status register.
2195 FPURegister left_reg = ToDoubleRegister(left);
2196 FPURegister right_reg = ToDoubleRegister(right);
2197
2198 // If a NaN is involved, i.e. the result is unordered,
2199 // jump to false block label.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002200 __ BranchF(NULL, instr->FalseLabel(chunk_), eq,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002201 left_reg, right_reg);
2202
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002203 EmitBranchF(instr, cond, left_reg, right_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002204 } else {
2205 Register cmp_left;
2206 Operand cmp_right = Operand(0);
2207
2208 if (right->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002209 int32_t value = ToInteger32(LConstantOperand::cast(right));
2210 if (instr->hydrogen_value()->representation().IsSmi()) {
2211 cmp_left = ToRegister(left);
2212 cmp_right = Operand(Smi::FromInt(value));
2213 } else {
2214 cmp_left = ToRegister(left);
2215 cmp_right = Operand(value);
2216 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002217 } else if (left->IsConstantOperand()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002218 int32_t value = ToInteger32(LConstantOperand::cast(left));
2219 if (instr->hydrogen_value()->representation().IsSmi()) {
2220 cmp_left = ToRegister(right);
2221 cmp_right = Operand(Smi::FromInt(value));
2222 } else {
2223 cmp_left = ToRegister(right);
2224 cmp_right = Operand(value);
2225 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002226 // We transposed the operands. Reverse the condition.
2227 cond = ReverseCondition(cond);
2228 } else {
2229 cmp_left = ToRegister(left);
2230 cmp_right = Operand(ToRegister(right));
2231 }
2232
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002233 EmitBranch(instr, cond, cmp_left, cmp_right);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002234 }
2235 }
2236}
2237
2238
2239void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002240 Register left = ToRegister(instr->left());
2241 Register right = ToRegister(instr->right());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002242
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002243 EmitBranch(instr, eq, left, Operand(right));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002244}
2245
2246
2247void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002248 Register left = ToRegister(instr->left());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002249
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002250 EmitBranch(instr, eq, left, Operand(instr->hydrogen()->right()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002251}
2252
2253
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002254Condition LCodeGen::EmitIsObject(Register input,
2255 Register temp1,
erikcorry0ad885c2011-11-21 13:51:57 +00002256 Register temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002257 Label* is_not_object,
2258 Label* is_object) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002259 __ JumpIfSmi(input, is_not_object);
2260
2261 __ LoadRoot(temp2, Heap::kNullValueRootIndex);
2262 __ Branch(is_object, eq, input, Operand(temp2));
2263
2264 // Load map.
2265 __ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
2266 // Undetectable objects behave like undefined.
2267 __ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
2268 __ And(temp2, temp2, Operand(1 << Map::kIsUndetectable));
2269 __ Branch(is_not_object, ne, temp2, Operand(zero_reg));
2270
2271 // Load instance type and check that it is in object type range.
2272 __ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
2273 __ Branch(is_not_object,
2274 lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2275
2276 return le;
2277}
2278
2279
2280void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002281 Register reg = ToRegister(instr->value());
2282 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002283 Register temp2 = scratch0();
2284
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002285 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002286 EmitIsObject(reg, temp1, temp2,
2287 instr->FalseLabel(chunk_), instr->TrueLabel(chunk_));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002288
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002289 EmitBranch(instr, true_cond, temp2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002290 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
2291}
2292
2293
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002294Condition LCodeGen::EmitIsString(Register input,
2295 Register temp1,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002296 Label* is_not_string,
2297 SmiCheck check_needed = INLINE_SMI_CHECK) {
2298 if (check_needed == INLINE_SMI_CHECK) {
2299 __ JumpIfSmi(input, is_not_string);
2300 }
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002301 __ GetObjectType(input, temp1, temp1);
2302
2303 return lt;
2304}
2305
2306
2307void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002308 Register reg = ToRegister(instr->value());
2309 Register temp1 = ToRegister(instr->temp());
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002310
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002311 SmiCheck check_needed =
2312 instr->hydrogen()->value()->IsHeapObject()
2313 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002314 Condition true_cond =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002315 EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002316
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002317 EmitBranch(instr, true_cond, temp1,
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002318 Operand(FIRST_NONSTRING_TYPE));
2319}
2320
2321
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002322void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002323 Register input_reg = EmitLoadRegister(instr->value(), at);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002324 __ And(at, input_reg, kSmiTagMask);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002325 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002326}
2327
2328
2329void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002330 Register input = ToRegister(instr->value());
2331 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002332
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002333 if (!instr->hydrogen()->value()->IsHeapObject()) {
2334 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2335 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002336 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset));
2337 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
2338 __ And(at, temp, Operand(1 << Map::kIsUndetectable));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002339 EmitBranch(instr, ne, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002340}
2341
2342
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002343static Condition ComputeCompareCondition(Token::Value op) {
2344 switch (op) {
2345 case Token::EQ_STRICT:
2346 case Token::EQ:
2347 return eq;
2348 case Token::LT:
2349 return lt;
2350 case Token::GT:
2351 return gt;
2352 case Token::LTE:
2353 return le;
2354 case Token::GTE:
2355 return ge;
2356 default:
2357 UNREACHABLE();
2358 return kNoCondition;
2359 }
2360}
2361
2362
2363void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
2364 Token::Value op = instr->op();
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002365
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002366 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002367 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2368
2369 Condition condition = ComputeCompareCondition(op);
2370
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002371 EmitBranch(instr, condition, v0, Operand(zero_reg));
mstarzinger@chromium.orgf8c6bd52011-11-23 12:13:52 +00002372}
2373
2374
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002375static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
2376 InstanceType from = instr->from();
2377 InstanceType to = instr->to();
2378 if (from == FIRST_TYPE) return to;
2379 ASSERT(from == to || to == LAST_TYPE);
2380 return from;
2381}
2382
2383
2384static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
2385 InstanceType from = instr->from();
2386 InstanceType to = instr->to();
2387 if (from == to) return eq;
2388 if (to == LAST_TYPE) return hs;
2389 if (from == FIRST_TYPE) return ls;
2390 UNREACHABLE();
2391 return eq;
2392}
2393
2394
2395void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
2396 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002397 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002398
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002399 if (!instr->hydrogen()->value()->IsHeapObject()) {
2400 __ JumpIfSmi(input, instr->FalseLabel(chunk_));
2401 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002402
2403 __ GetObjectType(input, scratch, scratch);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002404 EmitBranch(instr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002405 BranchCondition(instr->hydrogen()),
2406 scratch,
2407 Operand(TestType(instr->hydrogen())));
2408}
2409
2410
2411void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002412 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002413 Register result = ToRegister(instr->result());
2414
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002415 __ AssertString(input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002416
2417 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset));
2418 __ IndexFromHash(result, result);
2419}
2420
2421
2422void LCodeGen::DoHasCachedArrayIndexAndBranch(
2423 LHasCachedArrayIndexAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002424 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002425 Register scratch = scratch0();
2426
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002427 __ lw(scratch,
2428 FieldMemOperand(input, String::kHashFieldOffset));
2429 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002430 EmitBranch(instr, eq, at, Operand(zero_reg));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002431}
2432
2433
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002434// Branches to a label or falls through with the answer in flags. Trashes
2435// the temp registers, but not the input.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002436void LCodeGen::EmitClassOfTest(Label* is_true,
2437 Label* is_false,
2438 Handle<String>class_name,
2439 Register input,
2440 Register temp,
2441 Register temp2) {
2442 ASSERT(!input.is(temp));
ulan@chromium.org2efb9002012-01-19 15:36:35 +00002443 ASSERT(!input.is(temp2));
2444 ASSERT(!temp.is(temp2));
2445
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002446 __ JumpIfSmi(input, is_false);
2447
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002448 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002449 // Assuming the following assertions, we can use the same compares to test
2450 // for both being a function type and being in the object type range.
2451 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
2452 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2453 FIRST_SPEC_OBJECT_TYPE + 1);
2454 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2455 LAST_SPEC_OBJECT_TYPE - 1);
2456 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
2457
2458 __ GetObjectType(input, temp, temp2);
2459 __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2460 __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE));
2461 __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE));
2462 } else {
2463 // Faster code path to avoid two compares: subtract lower bound from the
2464 // actual type and do a signed compare with the width of the type range.
2465 __ GetObjectType(input, temp, temp2);
2466 __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2467 __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE -
2468 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
2469 }
2470
2471 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
2472 // Check if the constructor in the map is a function.
2473 __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset));
2474
2475 // Objects with a non-function constructor have class 'Object'.
2476 __ GetObjectType(temp, temp2, temp2);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002477 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002478 __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE));
2479 } else {
2480 __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE));
2481 }
2482
2483 // temp now contains the constructor function. Grab the
2484 // instance class name from there.
2485 __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2486 __ lw(temp, FieldMemOperand(temp,
2487 SharedFunctionInfo::kInstanceClassNameOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002488 // The class name we are testing against is internalized since it's a literal.
2489 // The name in the constructor is internalized because of the way the context
2490 // is booted. This routine isn't expected to work for random API-created
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002491 // classes and it doesn't have to because you can't access it with natives
ulan@chromium.org750145a2013-03-07 15:14:13 +00002492 // syntax. Since both sides are internalized it is sufficient to use an
2493 // identity comparison.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002494
2495 // End with the address of this class_name instance in temp register.
2496 // On MIPS, the caller must do the comparison with Handle<String>class_name.
2497}
2498
2499
2500void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002501 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002502 Register temp = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002503 Register temp2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002504 Handle<String> class_name = instr->hydrogen()->class_name();
2505
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002506 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_),
2507 class_name, input, temp, temp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002508
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002509 EmitBranch(instr, eq, temp, Operand(class_name));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002510}
2511
2512
2513void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002514 Register reg = ToRegister(instr->value());
2515 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002516
2517 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002518 EmitBranch(instr, eq, temp, Operand(instr->map()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002519}
2520
2521
2522void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
2523 Label true_label, done;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002524 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0.
2525 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002526 Register result = ToRegister(instr->result());
2527 ASSERT(result.is(v0));
2528
2529 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002530 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002531
2532 __ Branch(&true_label, eq, result, Operand(zero_reg));
2533 __ li(result, Operand(factory()->false_value()));
2534 __ Branch(&done);
2535 __ bind(&true_label);
2536 __ li(result, Operand(factory()->true_value()));
2537 __ bind(&done);
2538}
2539
2540
2541void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
2542 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2543 public:
2544 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2545 LInstanceOfKnownGlobal* instr)
2546 : LDeferredCode(codegen), instr_(instr) { }
2547 virtual void Generate() {
erikcorry0ad885c2011-11-21 13:51:57 +00002548 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002549 }
2550 virtual LInstruction* instr() { return instr_; }
2551 Label* map_check() { return &map_check_; }
2552
2553 private:
2554 LInstanceOfKnownGlobal* instr_;
2555 Label map_check_;
2556 };
2557
2558 DeferredInstanceOfKnownGlobal* deferred;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002559 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002560
2561 Label done, false_result;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002562 Register object = ToRegister(instr->value());
2563 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002564 Register result = ToRegister(instr->result());
2565
2566 ASSERT(object.is(a0));
2567 ASSERT(result.is(v0));
2568
2569 // A Smi is not instance of anything.
2570 __ JumpIfSmi(object, &false_result);
2571
2572 // This is the inlined call site instanceof cache. The two occurences of the
2573 // hole value will be patched to the last map/result pair generated by the
2574 // instanceof stub.
2575 Label cache_miss;
2576 Register map = temp;
2577 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset));
2578
2579 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
2580 __ bind(deferred->map_check()); // Label for calculating code patching.
2581 // We use Factory::the_hole_value() on purpose instead of loading from the
2582 // root array to force relocation to be able to later patch with
2583 // the cached map.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002584 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002585 __ li(at, Operand(Handle<Object>(cell)));
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00002586 __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002587 __ Branch(&cache_miss, ne, map, Operand(at));
2588 // We use Factory::the_hole_value() on purpose instead of loading from the
2589 // root array to force relocation to be able to later patch
2590 // with true or false.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002591 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002592 __ Branch(&done);
2593
2594 // The inlined call site cache did not match. Check null and string before
2595 // calling the deferred code.
2596 __ bind(&cache_miss);
2597 // Null is not instance of anything.
2598 __ LoadRoot(temp, Heap::kNullValueRootIndex);
2599 __ Branch(&false_result, eq, object, Operand(temp));
2600
2601 // String values is not instance of anything.
2602 Condition cc = __ IsObjectStringType(object, temp, temp);
2603 __ Branch(&false_result, cc, temp, Operand(zero_reg));
2604
2605 // Go to the deferred code.
2606 __ Branch(deferred->entry());
2607
2608 __ bind(&false_result);
2609 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2610
2611 // Here result has either true or false. Deferred code also produces true or
2612 // false object.
2613 __ bind(deferred->exit());
2614 __ bind(&done);
2615}
2616
2617
erikcorry0ad885c2011-11-21 13:51:57 +00002618void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2619 Label* map_check) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002620 Register result = ToRegister(instr->result());
2621 ASSERT(result.is(v0));
2622
2623 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2624 flags = static_cast<InstanceofStub::Flags>(
2625 flags | InstanceofStub::kArgsInRegisters);
2626 flags = static_cast<InstanceofStub::Flags>(
2627 flags | InstanceofStub::kCallSiteInlineCheck);
2628 flags = static_cast<InstanceofStub::Flags>(
2629 flags | InstanceofStub::kReturnTrueFalseObject);
2630 InstanceofStub stub(flags);
2631
2632 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
2633
2634 // Get the temp register reserved by the instruction. This needs to be t0 as
2635 // its slot of the pushing of safepoint registers is used to communicate the
2636 // offset to the location of the map check.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002637 Register temp = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002638 ASSERT(temp.is(t0));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002639 __ LoadHeapObject(InstanceofStub::right(), instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002640 static const int kAdditionalDelta = 7;
2641 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2642 Label before_push_delta;
2643 __ bind(&before_push_delta);
2644 {
2645 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002646 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002647 __ StoreToSafepointRegisterSlot(temp, temp);
2648 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002649 CallCodeGeneric(stub.GetCode(isolate()),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002650 RelocInfo::CODE_TARGET,
2651 instr,
2652 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00002653 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
erikcorry0ad885c2011-11-21 13:51:57 +00002654 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002655 // Put the result value into the result register slot and
2656 // restore all registers.
2657 __ StoreToSafepointRegisterSlot(result, result);
2658}
2659
2660
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002661void LCodeGen::DoInstanceSize(LInstanceSize* instr) {
2662 Register object = ToRegister(instr->object());
2663 Register result = ToRegister(instr->result());
2664 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
2665 __ lbu(result, FieldMemOperand(result, Map::kInstanceSizeOffset));
2666}
2667
2668
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002669void LCodeGen::DoCmpT(LCmpT* instr) {
2670 Token::Value op = instr->op();
2671
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002672 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002673 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2674 // On MIPS there is no need for a "no inlined smi code" marker (nop).
2675
2676 Condition condition = ComputeCompareCondition(op);
2677 // A minor optimization that relies on LoadRoot always emitting one
2678 // instruction.
2679 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
ulan@chromium.org750145a2013-03-07 15:14:13 +00002680 Label done, check;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002681 __ Branch(USE_DELAY_SLOT, &done, condition, v0, Operand(zero_reg));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002682 __ bind(&check);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002683 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002684 ASSERT_EQ(1, masm()->InstructionsGeneratedSince(&check));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002685 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002686 __ bind(&done);
2687}
2688
2689
2690void LCodeGen::DoReturn(LReturn* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002691 if (FLAG_trace && info()->IsOptimizing()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002692 // Push the return value on the stack as the parameter.
2693 // Runtime::TraceExit returns its parameter in v0.
2694 __ push(v0);
2695 __ CallRuntime(Runtime::kTraceExit, 1);
2696 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00002697 if (info()->saves_caller_doubles()) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002698 ASSERT(NeedsEagerFrame());
2699 BitVector* doubles = chunk()->allocated_double_registers();
2700 BitVector::Iterator save_iterator(doubles);
2701 int count = 0;
2702 while (!save_iterator.Done()) {
2703 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()),
2704 MemOperand(sp, count * kDoubleSize));
2705 save_iterator.Advance();
2706 count++;
2707 }
2708 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002709 int no_frame_start = -1;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002710 if (NeedsEagerFrame()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002711 __ mov(sp, fp);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002712 no_frame_start = masm_->pc_offset();
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002713 __ Pop(ra, fp);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002714 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002715 if (instr->has_constant_parameter_count()) {
2716 int parameter_count = ToInteger32(instr->constant_parameter_count());
2717 int32_t sp_delta = (parameter_count + 1) * kPointerSize;
2718 if (sp_delta != 0) {
2719 __ Addu(sp, sp, Operand(sp_delta));
2720 }
2721 } else {
2722 Register reg = ToRegister(instr->parameter_count());
2723 // The argument count parameter is a smi
2724 __ SmiUntag(reg);
2725 __ sll(at, reg, kPointerSizeLog2);
2726 __ Addu(sp, sp, at);
2727 }
2728
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002729 __ Jump(ra);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002730
2731 if (no_frame_start != -1) {
2732 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
2733 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002734}
2735
2736
2737void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2738 Register result = ToRegister(instr->result());
2739 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell())));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002740 __ lw(result, FieldMemOperand(at, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002741 if (instr->hydrogen()->RequiresHoleCheck()) {
2742 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2743 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2744 }
2745}
2746
2747
2748void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2749 ASSERT(ToRegister(instr->global_object()).is(a0));
2750 ASSERT(ToRegister(instr->result()).is(v0));
2751
2752 __ li(a2, Operand(instr->name()));
2753 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET
2754 : RelocInfo::CODE_TARGET_CONTEXT;
2755 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2756 CallCode(ic, mode, instr);
2757}
2758
2759
2760void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002761 Register value = ToRegister(instr->value());
2762 Register cell = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002763
2764 // Load the cell.
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002765 __ li(cell, Operand(instr->hydrogen()->cell()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002766
2767 // If the cell we are storing to contains the hole it could have
2768 // been deleted from the property dictionary. In that case, we need
2769 // to update the property details in the property dictionary to mark
2770 // it as no longer deleted.
2771 if (instr->hydrogen()->RequiresHoleCheck()) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002772 // We use a temp to check the payload.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002773 Register payload = ToRegister(instr->temp());
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002774 __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002775 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00002776 DeoptimizeIf(eq, instr->environment(), payload, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002777 }
2778
2779 // Store the value.
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002780 __ sw(value, FieldMemOperand(cell, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002781 // Cells are always rescanned, so no write barrier here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002782}
2783
2784
2785void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2786 ASSERT(ToRegister(instr->global_object()).is(a1));
2787 ASSERT(ToRegister(instr->value()).is(a0));
2788
2789 __ li(a2, Operand(instr->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002790 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002791 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2792 : isolate()->builtins()->StoreIC_Initialize();
2793 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2794}
2795
2796
2797void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2798 Register context = ToRegister(instr->context());
2799 Register result = ToRegister(instr->result());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002800
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002801 __ lw(result, ContextOperand(context, instr->slot_index()));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002802 if (instr->hydrogen()->RequiresHoleCheck()) {
2803 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002804
2805 if (instr->hydrogen()->DeoptimizesOnHole()) {
2806 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2807 } else {
2808 Label is_not_hole;
2809 __ Branch(&is_not_hole, ne, result, Operand(at));
2810 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2811 __ bind(&is_not_hole);
2812 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002813 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002814}
2815
2816
2817void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2818 Register context = ToRegister(instr->context());
2819 Register value = ToRegister(instr->value());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002820 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002821 MemOperand target = ContextOperand(context, instr->slot_index());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002822
2823 Label skip_assignment;
2824
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002825 if (instr->hydrogen()->RequiresHoleCheck()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002826 __ lw(scratch, target);
2827 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002828
2829 if (instr->hydrogen()->DeoptimizesOnHole()) {
2830 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
2831 } else {
2832 __ Branch(&skip_assignment, ne, scratch, Operand(at));
2833 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002834 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002835
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002836 __ sw(value, target);
2837 if (instr->hydrogen()->NeedsWriteBarrier()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002838 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002839 instr->hydrogen()->value()->IsHeapObject()
2840 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002841 __ RecordWriteContextSlot(context,
2842 target.offset(),
2843 value,
2844 scratch0(),
danno@chromium.orgc99cd482013-03-21 15:26:42 +00002845 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002846 kSaveFPRegs,
2847 EMIT_REMEMBERED_SET,
2848 check_needed);
2849 }
ricow@chromium.org7ad65222011-12-19 12:13:11 +00002850
2851 __ bind(&skip_assignment);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002852}
2853
2854
2855void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002856 HObjectAccess access = instr->hydrogen()->access();
2857 int offset = access.offset();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002858 Register object = ToRegister(instr->object());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002859 if (instr->hydrogen()->representation().IsDouble()) {
2860 DoubleRegister result = ToDoubleRegister(instr->result());
2861 __ ldc1(result, FieldMemOperand(object, offset));
2862 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002863 }
2864
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002865 Register result = ToRegister(instr->result());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00002866 if (access.IsInobject()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002867 __ lw(result, FieldMemOperand(object, offset));
2868 } else {
2869 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2870 __ lw(result, FieldMemOperand(result, offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002871 }
2872}
2873
2874
2875void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2876 Register object,
2877 Handle<Map> type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002878 Handle<String> name,
2879 LEnvironment* env) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002880 LookupResult lookup(isolate());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002881 type->LookupDescriptor(NULL, *name, &lookup);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002882 ASSERT(lookup.IsFound() || lookup.IsCacheable());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002883 if (lookup.IsField()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002884 int index = lookup.GetLocalFieldIndexFromMap(*type);
2885 int offset = index * kPointerSize;
2886 if (index < 0) {
2887 // Negative property indices are in-object properties, indexed
2888 // from the end of the fixed part of the object.
2889 __ lw(result, FieldMemOperand(object, offset + type->instance_size()));
2890 } else {
2891 // Non-negative property indices are in the properties array.
2892 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2893 __ lw(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
2894 }
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002895 } else if (lookup.IsConstantFunction()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002896 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002897 __ LoadHeapObject(result, function);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002898 } else {
2899 // Negative lookup.
2900 // Check prototypes.
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002901 Handle<HeapObject> current(HeapObject::cast((*type)->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002902 Heap* heap = type->GetHeap();
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002903 while (*current != heap->null_value()) {
2904 __ LoadHeapObject(result, current);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002905 __ lw(result, FieldMemOperand(result, HeapObject::kMapOffset));
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002906 DeoptimizeIf(ne, env, result, Operand(Handle<Map>(current->map())));
2907 current =
2908 Handle<HeapObject>(HeapObject::cast(current->map()->prototype()));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002909 }
2910 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002911 }
2912}
2913
2914
2915void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2916 Register object = ToRegister(instr->object());
2917 Register result = ToRegister(instr->result());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002918 Register object_map = scratch0();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002920 int map_count = instr->hydrogen()->types()->length();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002921 bool need_generic = instr->hydrogen()->need_generic();
2922
2923 if (map_count == 0 && !need_generic) {
2924 DeoptimizeIf(al, instr->environment());
2925 return;
2926 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002927 Handle<String> name = instr->hydrogen()->name();
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002928 Label done;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002929 __ lw(object_map, FieldMemOperand(object, HeapObject::kMapOffset));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002930 for (int i = 0; i < map_count; ++i) {
2931 bool last = (i == map_count - 1);
2932 Handle<Map> map = instr->hydrogen()->types()->at(i);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002933 Label check_passed;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00002934 __ CompareMapAndBranch(object_map, map, &check_passed, eq, &check_passed);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002935 if (last && !need_generic) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002936 DeoptimizeIf(al, instr->environment());
2937 __ bind(&check_passed);
2938 EmitLoadFieldOrConstantFunction(
2939 result, object, map, name, instr->environment());
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002940 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002941 Label next;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002942 __ Branch(&next);
2943 __ bind(&check_passed);
2944 EmitLoadFieldOrConstantFunction(
2945 result, object, map, name, instr->environment());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002946 __ Branch(&done);
2947 __ bind(&next);
2948 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002949 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002950 if (need_generic) {
2951 __ li(a2, Operand(name));
2952 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2953 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2954 }
2955 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002956}
2957
2958
2959void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
2960 ASSERT(ToRegister(instr->object()).is(a0));
2961 ASSERT(ToRegister(instr->result()).is(v0));
2962
2963 // Name is always in a2.
2964 __ li(a2, Operand(instr->name()));
2965 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2966 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2967}
2968
2969
2970void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
2971 Register scratch = scratch0();
2972 Register function = ToRegister(instr->function());
2973 Register result = ToRegister(instr->result());
2974
2975 // Check that the function really is a function. Load map into the
2976 // result register.
2977 __ GetObjectType(function, result, scratch);
2978 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_FUNCTION_TYPE));
2979
2980 // Make sure that the function has an instance prototype.
2981 Label non_instance;
2982 __ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
2983 __ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
2984 __ Branch(&non_instance, ne, scratch, Operand(zero_reg));
2985
2986 // Get the prototype or initial map from the function.
2987 __ lw(result,
2988 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2989
2990 // Check that the function has a prototype or an initial map.
2991 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2992 DeoptimizeIf(eq, instr->environment(), result, Operand(at));
2993
2994 // If the function does not have an initial map, we're done.
2995 Label done;
2996 __ GetObjectType(result, scratch, scratch);
2997 __ Branch(&done, ne, scratch, Operand(MAP_TYPE));
2998
2999 // Get the prototype from the initial map.
3000 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset));
3001 __ Branch(&done);
3002
3003 // Non-instance prototype: Fetch prototype from constructor field
3004 // in initial map.
3005 __ bind(&non_instance);
3006 __ lw(result, FieldMemOperand(result, Map::kConstructorOffset));
3007
3008 // All done.
3009 __ bind(&done);
3010}
3011
3012
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003013void LCodeGen::DoLoadExternalArrayPointer(
3014 LLoadExternalArrayPointer* instr) {
3015 Register to_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003016 Register from_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003017 __ lw(to_reg, FieldMemOperand(from_reg,
3018 ExternalArray::kExternalPointerOffset));
3019}
3020
3021
3022void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
3023 Register arguments = ToRegister(instr->arguments());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003024 Register result = ToRegister(instr->result());
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003025 if (instr->length()->IsConstantOperand() &&
3026 instr->index()->IsConstantOperand()) {
3027 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3028 int const_length = ToInteger32(LConstantOperand::cast(instr->length()));
3029 int index = (const_length - const_index) + 1;
3030 __ lw(result, MemOperand(arguments, index * kPointerSize));
3031 } else {
3032 Register length = ToRegister(instr->length());
3033 Register index = ToRegister(instr->index());
3034 // There are two words between the frame pointer and the last argument.
3035 // Subtracting from length accounts for one of them, add one more.
3036 __ subu(length, length, index);
3037 __ Addu(length, length, Operand(1));
3038 __ sll(length, length, kPointerSizeLog2);
3039 __ Addu(at, arguments, Operand(length));
3040 __ lw(result, MemOperand(at, 0));
3041 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003042}
3043
3044
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003045void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) {
3046 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003047 Register key = no_reg;
3048 ElementsKind elements_kind = instr->elements_kind();
3049 bool key_is_constant = instr->key()->IsConstantOperand();
3050 int constant_key = 0;
3051 if (key_is_constant) {
3052 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
3053 if (constant_key & 0xF0000000) {
3054 Abort("array index constant value too big.");
3055 }
3056 } else {
3057 key = ToRegister(instr->key());
3058 }
danno@chromium.org129d3982012-07-25 15:01:47 +00003059 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003060 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00003061 ? (element_size_shift - kSmiTagSize) : element_size_shift;
3062 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003063
3064 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
3065 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
3066 FPURegister result = ToDoubleRegister(instr->result());
3067 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00003068 __ Addu(scratch0(), external_pointer, constant_key << element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003069 } else {
3070 __ sll(scratch0(), key, shift_size);
3071 __ Addu(scratch0(), scratch0(), external_pointer);
3072 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003073 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
3074 __ lwc1(result, MemOperand(scratch0(), additional_offset));
3075 __ cvt_d_s(result, result);
3076 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
3077 __ ldc1(result, MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003078 }
3079 } else {
3080 Register result = ToRegister(instr->result());
danno@chromium.org129d3982012-07-25 15:01:47 +00003081 MemOperand mem_operand = PrepareKeyedOperand(
3082 key, external_pointer, key_is_constant, constant_key,
3083 element_size_shift, shift_size,
3084 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003085 switch (elements_kind) {
3086 case EXTERNAL_BYTE_ELEMENTS:
3087 __ lb(result, mem_operand);
3088 break;
3089 case EXTERNAL_PIXEL_ELEMENTS:
3090 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3091 __ lbu(result, mem_operand);
3092 break;
3093 case EXTERNAL_SHORT_ELEMENTS:
3094 __ lh(result, mem_operand);
3095 break;
3096 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3097 __ lhu(result, mem_operand);
3098 break;
3099 case EXTERNAL_INT_ELEMENTS:
3100 __ lw(result, mem_operand);
3101 break;
3102 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3103 __ lw(result, mem_operand);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00003104 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
3105 DeoptimizeIf(Ugreater_equal, instr->environment(),
3106 result, Operand(0x80000000));
3107 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003108 break;
3109 case EXTERNAL_FLOAT_ELEMENTS:
3110 case EXTERNAL_DOUBLE_ELEMENTS:
3111 case FAST_DOUBLE_ELEMENTS:
3112 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003113 case FAST_SMI_ELEMENTS:
3114 case FAST_HOLEY_DOUBLE_ELEMENTS:
3115 case FAST_HOLEY_ELEMENTS:
3116 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003117 case DICTIONARY_ELEMENTS:
3118 case NON_STRICT_ARGUMENTS_ELEMENTS:
3119 UNREACHABLE();
3120 break;
3121 }
3122 }
3123}
3124
3125
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003126void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) {
3127 Register elements = ToRegister(instr->elements());
3128 bool key_is_constant = instr->key()->IsConstantOperand();
3129 Register key = no_reg;
3130 DoubleRegister result = ToDoubleRegister(instr->result());
3131 Register scratch = scratch0();
3132
3133 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003134 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003135 ? (element_size_shift - kSmiTagSize) : element_size_shift;
3136 int constant_key = 0;
3137 if (key_is_constant) {
3138 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
3139 if (constant_key & 0xF0000000) {
3140 Abort("array index constant value too big.");
3141 }
3142 } else {
3143 key = ToRegister(instr->key());
3144 }
3145
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003146 int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) +
3147 ((constant_key + instr->additional_index()) << element_size_shift);
3148 if (!key_is_constant) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003149 __ sll(scratch, key, shift_size);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003150 __ Addu(elements, elements, scratch);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003151 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003152 __ Addu(elements, elements, Operand(base_offset));
3153 __ ldc1(result, MemOperand(elements));
3154 if (instr->hydrogen()->RequiresHoleCheck()) {
3155 __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
3156 DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003157 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003158}
3159
3160
3161void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) {
3162 Register elements = ToRegister(instr->elements());
3163 Register result = ToRegister(instr->result());
3164 Register scratch = scratch0();
3165 Register store_base = scratch;
3166 int offset = 0;
3167
3168 if (instr->key()->IsConstantOperand()) {
3169 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3170 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
3171 instr->additional_index());
3172 store_base = elements;
3173 } else {
3174 Register key = EmitLoadRegister(instr->key(), scratch0());
3175 // Even though the HLoadKeyed instruction forces the input
3176 // representation for the key to be an integer, the input gets replaced
3177 // during bound check elimination with the index argument to the bounds
3178 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003179 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003180 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
3181 __ addu(scratch, elements, scratch);
3182 } else {
3183 __ sll(scratch, key, kPointerSizeLog2);
3184 __ addu(scratch, elements, scratch);
3185 }
3186 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
3187 }
3188 __ lw(result, FieldMemOperand(store_base, offset));
3189
3190 // Check for the hole value.
3191 if (instr->hydrogen()->RequiresHoleCheck()) {
3192 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
3193 __ And(scratch, result, Operand(kSmiTagMask));
3194 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3195 } else {
3196 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
3197 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch));
3198 }
3199 }
3200}
3201
3202
3203void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) {
3204 if (instr->is_external()) {
3205 DoLoadKeyedExternalArray(instr);
3206 } else if (instr->hydrogen()->representation().IsDouble()) {
3207 DoLoadKeyedFixedDoubleArray(instr);
3208 } else {
3209 DoLoadKeyedFixedArray(instr);
3210 }
3211}
3212
3213
3214MemOperand LCodeGen::PrepareKeyedOperand(Register key,
3215 Register base,
3216 bool key_is_constant,
3217 int constant_key,
3218 int element_size,
3219 int shift_size,
3220 int additional_index,
3221 int additional_offset) {
3222 if (additional_index != 0 && !key_is_constant) {
3223 additional_index *= 1 << (element_size - shift_size);
3224 __ Addu(scratch0(), key, Operand(additional_index));
3225 }
3226
3227 if (key_is_constant) {
3228 return MemOperand(base,
3229 (constant_key << element_size) + additional_offset);
3230 }
3231
3232 if (additional_index == 0) {
3233 if (shift_size >= 0) {
3234 __ sll(scratch0(), key, shift_size);
3235 __ Addu(scratch0(), base, scratch0());
3236 return MemOperand(scratch0());
3237 } else {
3238 ASSERT_EQ(-1, shift_size);
3239 __ srl(scratch0(), key, 1);
3240 __ Addu(scratch0(), base, scratch0());
3241 return MemOperand(scratch0());
3242 }
3243 }
3244
3245 if (shift_size >= 0) {
3246 __ sll(scratch0(), scratch0(), shift_size);
3247 __ Addu(scratch0(), base, scratch0());
3248 return MemOperand(scratch0());
3249 } else {
3250 ASSERT_EQ(-1, shift_size);
3251 __ srl(scratch0(), scratch0(), 1);
3252 __ Addu(scratch0(), base, scratch0());
3253 return MemOperand(scratch0());
3254 }
3255}
3256
3257
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003258void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
3259 ASSERT(ToRegister(instr->object()).is(a1));
3260 ASSERT(ToRegister(instr->key()).is(a0));
3261
3262 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
3263 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3264}
3265
3266
3267void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
3268 Register scratch = scratch0();
3269 Register temp = scratch1();
3270 Register result = ToRegister(instr->result());
3271
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003272 if (instr->hydrogen()->from_inlined()) {
3273 __ Subu(result, sp, 2 * kPointerSize);
3274 } else {
3275 // Check if the calling frame is an arguments adaptor frame.
3276 Label done, adapted;
3277 __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3278 __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
3279 __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003280
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003281 // Result is the frame pointer for the frame if not adapted and for the real
3282 // frame below the adaptor frame if adapted.
3283 __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne).
3284 __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq).
3285 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003286}
3287
3288
3289void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003290 Register elem = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003291 Register result = ToRegister(instr->result());
3292
3293 Label done;
3294
3295 // If no arguments adaptor frame the number of arguments is fixed.
3296 __ Addu(result, zero_reg, Operand(scope()->num_parameters()));
3297 __ Branch(&done, eq, fp, Operand(elem));
3298
3299 // Arguments adaptor frame present. Get argument length from there.
3300 __ lw(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3301 __ lw(result,
3302 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
3303 __ SmiUntag(result);
3304
3305 // Argument length is in result register.
3306 __ bind(&done);
3307}
3308
3309
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003310void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003311 Register receiver = ToRegister(instr->receiver());
3312 Register function = ToRegister(instr->function());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003313 Register scratch = scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003314
3315 // If the receiver is null or undefined, we have to pass the global
3316 // object as a receiver to normal functions. Values have to be
3317 // passed unchanged to builtins and strict-mode functions.
3318 Label global_object, receiver_ok;
3319
3320 // Do not transform the receiver to object for strict mode
3321 // functions.
3322 __ lw(scratch,
3323 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
3324 __ lw(scratch,
3325 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
3326
3327 // Do not transform the receiver to object for builtins.
3328 int32_t strict_mode_function_mask =
3329 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
3330 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
3331 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask));
3332 __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg));
3333
3334 // Normal function. Replace undefined or null with global receiver.
3335 __ LoadRoot(scratch, Heap::kNullValueRootIndex);
3336 __ Branch(&global_object, eq, receiver, Operand(scratch));
3337 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
3338 __ Branch(&global_object, eq, receiver, Operand(scratch));
3339
3340 // Deoptimize if the receiver is not a JS object.
3341 __ And(scratch, receiver, Operand(kSmiTagMask));
3342 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
3343
3344 __ GetObjectType(receiver, scratch, scratch);
3345 DeoptimizeIf(lt, instr->environment(),
3346 scratch, Operand(FIRST_SPEC_OBJECT_TYPE));
3347 __ Branch(&receiver_ok);
3348
3349 __ bind(&global_object);
3350 __ lw(receiver, GlobalObjectOperand());
3351 __ lw(receiver,
3352 FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
3353 __ bind(&receiver_ok);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003354}
3355
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003356
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003357void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
3358 Register receiver = ToRegister(instr->receiver());
3359 Register function = ToRegister(instr->function());
3360 Register length = ToRegister(instr->length());
3361 Register elements = ToRegister(instr->elements());
3362 Register scratch = scratch0();
3363 ASSERT(receiver.is(a0)); // Used for parameter count.
3364 ASSERT(function.is(a1)); // Required by InvokeFunction.
3365 ASSERT(ToRegister(instr->result()).is(v0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003366
3367 // Copy the arguments to this function possibly from the
3368 // adaptor frame below it.
3369 const uint32_t kArgumentsLimit = 1 * KB;
3370 DeoptimizeIf(hi, instr->environment(), length, Operand(kArgumentsLimit));
3371
3372 // Push the receiver and use the register to keep the original
3373 // number of arguments.
3374 __ push(receiver);
3375 __ Move(receiver, length);
3376 // The arguments are at a one pointer size offset from elements.
3377 __ Addu(elements, elements, Operand(1 * kPointerSize));
3378
3379 // Loop through the arguments pushing them onto the execution
3380 // stack.
3381 Label invoke, loop;
3382 // length is a small non-negative integer, due to the test above.
3383 __ Branch(USE_DELAY_SLOT, &invoke, eq, length, Operand(zero_reg));
3384 __ sll(scratch, length, 2);
3385 __ bind(&loop);
3386 __ Addu(scratch, elements, scratch);
3387 __ lw(scratch, MemOperand(scratch));
3388 __ push(scratch);
3389 __ Subu(length, length, Operand(1));
3390 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg));
3391 __ sll(scratch, length, 2);
3392
3393 __ bind(&invoke);
danno@chromium.orge4bfb262012-05-04 10:50:07 +00003394 ASSERT(instr->HasPointerMap());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003395 LPointerMap* pointers = instr->pointer_map();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003396 RecordPosition(pointers->position());
erikcorry0ad885c2011-11-21 13:51:57 +00003397 SafepointGenerator safepoint_generator(
3398 this, pointers, Safepoint::kLazyDeopt);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003399 // The number of arguments is stored in receiver which is a0, as expected
3400 // by InvokeFunction.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003401 ParameterCount actual(receiver);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003402 __ InvokeFunction(function, actual, CALL_FUNCTION,
3403 safepoint_generator, CALL_AS_METHOD);
3404 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3405}
3406
3407
3408void LCodeGen::DoPushArgument(LPushArgument* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003409 LOperand* argument = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003410 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
3411 Abort("DoPushArgument not implemented for double type.");
3412 } else {
3413 Register argument_reg = EmitLoadRegister(argument, at);
3414 __ push(argument_reg);
3415 }
3416}
3417
3418
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00003419void LCodeGen::DoDrop(LDrop* instr) {
3420 __ Drop(instr->count());
3421}
3422
3423
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003424void LCodeGen::DoThisFunction(LThisFunction* instr) {
3425 Register result = ToRegister(instr->result());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00003426 __ lw(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003427}
3428
3429
3430void LCodeGen::DoContext(LContext* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003431 // If there is a non-return use, the context must be moved to a register.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003432 Register result = ToRegister(instr->result());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00003433 for (HUseIterator it(instr->hydrogen()->uses()); !it.Done(); it.Advance()) {
3434 if (!it.value()->IsReturn()) {
3435 __ mov(result, cp);
3436 return;
3437 }
3438 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003439}
3440
3441
3442void LCodeGen::DoOuterContext(LOuterContext* instr) {
3443 Register context = ToRegister(instr->context());
3444 Register result = ToRegister(instr->result());
3445 __ lw(result,
3446 MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
3447}
3448
3449
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003450void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
3451 __ LoadHeapObject(scratch0(), instr->hydrogen()->pairs());
3452 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags())));
3453 // The context is the first argument.
3454 __ Push(cp, scratch0(), scratch1());
3455 CallRuntime(Runtime::kDeclareGlobals, 3, instr);
3456}
3457
3458
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003459void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003460 Register result = ToRegister(instr->result());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003461 __ lw(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003462}
3463
3464
3465void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003466 Register global = ToRegister(instr->global_object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003467 Register result = ToRegister(instr->result());
3468 __ lw(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
3469}
3470
3471
3472void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003473 int formal_parameter_count,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003474 int arity,
3475 LInstruction* instr,
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003476 CallKind call_kind,
3477 A1State a1_state) {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003478 bool dont_adapt_arguments =
3479 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3480 bool can_invoke_directly =
3481 dont_adapt_arguments || formal_parameter_count == arity;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003482
3483 LPointerMap* pointers = instr->pointer_map();
3484 RecordPosition(pointers->position());
3485
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003486 if (can_invoke_directly) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003487 if (a1_state == A1_UNINITIALIZED) {
3488 __ LoadHeapObject(a1, function);
3489 }
3490
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00003491 // Change context.
3492 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003493
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003494 // Set r0 to arguments count if adaption is not needed. Assumes that r0
3495 // is available to write to at this point.
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003496 if (dont_adapt_arguments) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003497 __ li(a0, Operand(arity));
3498 }
3499
3500 // Invoke function.
3501 __ SetCallKind(t1, call_kind);
3502 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
3503 __ Call(at);
3504
3505 // Set up deoptimization.
3506 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
3507 } else {
3508 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3509 ParameterCount count(arity);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003510 ParameterCount expected(formal_parameter_count);
3511 __ InvokeFunction(
3512 function, expected, count, CALL_FUNCTION, generator, call_kind);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00003513 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003514
3515 // Restore context.
3516 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3517}
3518
3519
3520void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
3521 ASSERT(ToRegister(instr->result()).is(v0));
3522 __ mov(a0, v0);
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003523 CallKnownFunction(instr->hydrogen()->function(),
3524 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003525 instr->arity(),
3526 instr,
3527 CALL_AS_METHOD,
3528 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003529}
3530
3531
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003532void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003533 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003534 Register result = ToRegister(instr->result());
3535 Register scratch = scratch0();
3536
3537 // Deoptimize if not a heap number.
3538 __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
3539 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3540 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at));
3541
3542 Label done;
3543 Register exponent = scratch0();
3544 scratch = no_reg;
3545 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3546 // Check the sign of the argument. If the argument is positive, just
3547 // return it.
3548 __ Move(result, input);
3549 __ And(at, exponent, Operand(HeapNumber::kSignMask));
3550 __ Branch(&done, eq, at, Operand(zero_reg));
3551
3552 // Input is negative. Reverse its sign.
3553 // Preserve the value of all registers.
3554 {
3555 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3556
3557 // Registers were saved at the safepoint, so we can use
3558 // many scratch registers.
3559 Register tmp1 = input.is(a1) ? a0 : a1;
3560 Register tmp2 = input.is(a2) ? a0 : a2;
3561 Register tmp3 = input.is(a3) ? a0 : a3;
3562 Register tmp4 = input.is(t0) ? a0 : t0;
3563
3564 // exponent: floating point exponent value.
3565
3566 Label allocated, slow;
3567 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
3568 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
3569 __ Branch(&allocated);
3570
3571 // Slow case: Call the runtime system to do the number allocation.
3572 __ bind(&slow);
3573
3574 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
3575 // Set the pointer to the new heap number in tmp.
3576 if (!tmp1.is(v0))
3577 __ mov(tmp1, v0);
3578 // Restore input_reg after call to runtime.
3579 __ LoadFromSafepointRegisterSlot(input, input);
3580 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
3581
3582 __ bind(&allocated);
3583 // exponent: floating point exponent value.
3584 // tmp1: allocated heap number.
3585 __ And(exponent, exponent, Operand(~HeapNumber::kSignMask));
3586 __ sw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
3587 __ lw(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
3588 __ sw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
3589
3590 __ StoreToSafepointRegisterSlot(tmp1, result);
3591 }
3592
3593 __ bind(&done);
3594}
3595
3596
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003597void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003598 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003599 Register result = ToRegister(instr->result());
3600 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
3601 Label done;
3602 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg));
3603 __ mov(result, input);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003604 __ subu(result, zero_reg, input);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003605 // Overflow if result is still negative, i.e. 0x80000000.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003606 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg));
3607 __ bind(&done);
3608}
3609
3610
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003611void LCodeGen::DoMathAbs(LMathAbs* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003612 // Class for deferred case.
3613 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
3614 public:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003615 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003616 : LDeferredCode(codegen), instr_(instr) { }
3617 virtual void Generate() {
3618 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3619 }
3620 virtual LInstruction* instr() { return instr_; }
3621 private:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003622 LMathAbs* instr_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003623 };
3624
3625 Representation r = instr->hydrogen()->value()->representation();
3626 if (r.IsDouble()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003627 FPURegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003628 FPURegister result = ToDoubleRegister(instr->result());
3629 __ abs_d(result, input);
3630 } else if (r.IsInteger32()) {
3631 EmitIntegerMathAbs(instr);
3632 } else {
3633 // Representation is tagged.
3634 DeferredMathAbsTaggedHeapNumber* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003635 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003636 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003637 // Smi check.
3638 __ JumpIfNotSmi(input, deferred->entry());
3639 // If smi, handle it directly.
3640 EmitIntegerMathAbs(instr);
3641 __ bind(deferred->exit());
3642 }
3643}
3644
3645
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003646void LCodeGen::DoMathFloor(LMathFloor* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003647 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003648 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003649 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003650 Register except_flag = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003651
3652 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003653 result,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003654 input,
3655 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003656 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003657 except_flag);
3658
3659 // Deopt if the operation did not succeed.
3660 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3661
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003662 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3663 // Test for -0.
3664 Label done;
3665 __ Branch(&done, ne, result, Operand(zero_reg));
3666 __ mfc1(scratch1, input.high());
3667 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
3668 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
3669 __ bind(&done);
3670 }
3671}
3672
3673
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003674void LCodeGen::DoMathRound(LMathRound* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003675 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003676 Register result = ToRegister(instr->result());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003677 DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003678 Register scratch = scratch0();
3679 Label done, check_sign_on_zero;
3680
3681 // Extract exponent bits.
3682 __ mfc1(result, input.high());
3683 __ Ext(scratch,
3684 result,
3685 HeapNumber::kExponentShift,
3686 HeapNumber::kExponentBits);
3687
3688 // If the number is in ]-0.5, +0.5[, the result is +/- 0.
3689 Label skip1;
3690 __ Branch(&skip1, gt, scratch, Operand(HeapNumber::kExponentBias - 2));
3691 __ mov(result, zero_reg);
3692 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3693 __ Branch(&check_sign_on_zero);
3694 } else {
3695 __ Branch(&done);
3696 }
3697 __ bind(&skip1);
3698
3699 // The following conversion will not work with numbers
3700 // outside of ]-2^32, 2^32[.
3701 DeoptimizeIf(ge, instr->environment(), scratch,
3702 Operand(HeapNumber::kExponentBias + 32));
3703
3704 // Save the original sign for later comparison.
3705 __ And(scratch, result, Operand(HeapNumber::kSignMask));
3706
3707 __ Move(double_scratch0(), 0.5);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003708 __ add_d(double_scratch0(), input, double_scratch0());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003709
3710 // Check sign of the result: if the sign changed, the input
3711 // value was in ]0.5, 0[ and the result should be -0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003712 __ mfc1(result, double_scratch0().high());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003713 __ Xor(result, result, Operand(scratch));
3714 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3715 // ARM uses 'mi' here, which is 'lt'
3716 DeoptimizeIf(lt, instr->environment(), result,
3717 Operand(zero_reg));
3718 } else {
3719 Label skip2;
3720 // ARM uses 'mi' here, which is 'lt'
3721 // Negating it results in 'ge'
3722 __ Branch(&skip2, ge, result, Operand(zero_reg));
3723 __ mov(result, zero_reg);
3724 __ Branch(&done);
3725 __ bind(&skip2);
3726 }
3727
3728 Register except_flag = scratch;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003729 __ EmitFPUTruncate(kRoundToMinusInf,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003730 result,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003731 double_scratch0(),
3732 at,
3733 double_scratch1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003734 except_flag);
3735
3736 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
3737
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003738 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3739 // Test for -0.
3740 __ Branch(&done, ne, result, Operand(zero_reg));
3741 __ bind(&check_sign_on_zero);
3742 __ mfc1(scratch, input.high());
3743 __ And(scratch, scratch, Operand(HeapNumber::kSignMask));
3744 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
3745 }
3746 __ bind(&done);
3747}
3748
3749
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003750void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003751 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003752 DoubleRegister result = ToDoubleRegister(instr->result());
3753 __ sqrt_d(result, input);
3754}
3755
3756
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003757void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003758 DoubleRegister input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003759 DoubleRegister result = ToDoubleRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003760 DoubleRegister temp = ToDoubleRegister(instr->temp());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003761
3762 ASSERT(!input.is(result));
3763
3764 // Note that according to ECMA-262 15.8.2.13:
3765 // Math.pow(-Infinity, 0.5) == Infinity
3766 // Math.sqrt(-Infinity) == NaN
3767 Label done;
3768 __ Move(temp, -V8_INFINITY);
3769 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input);
3770 // Set up Infinity in the delay slot.
3771 // result is overwritten if the branch is not taken.
3772 __ neg_d(result, temp);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003773
3774 // Add +0 to convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003775 __ add_d(result, input, kDoubleRegZero);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003776 __ sqrt_d(result, result);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003777 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003778}
3779
3780
3781void LCodeGen::DoPower(LPower* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003782 Representation exponent_type = instr->hydrogen()->right()->representation();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003783 // Having marked this as a call, we can use any registers.
3784 // Just make sure that the input/output registers are the expected ones.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003785 ASSERT(!instr->right()->IsDoubleRegister() ||
3786 ToDoubleRegister(instr->right()).is(f4));
3787 ASSERT(!instr->right()->IsRegister() ||
3788 ToRegister(instr->right()).is(a2));
3789 ASSERT(ToDoubleRegister(instr->left()).is(f2));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003790 ASSERT(ToDoubleRegister(instr->result()).is(f0));
3791
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00003792 if (exponent_type.IsSmi()) {
3793 MathPowStub stub(MathPowStub::TAGGED);
3794 __ CallStub(&stub);
3795 } else if (exponent_type.IsTagged()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003796 Label no_deopt;
3797 __ JumpIfSmi(a2, &no_deopt);
3798 __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset));
3799 DeoptimizeIf(ne, instr->environment(), t3, Operand(at));
3800 __ bind(&no_deopt);
3801 MathPowStub stub(MathPowStub::TAGGED);
3802 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003803 } else if (exponent_type.IsInteger32()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003804 MathPowStub stub(MathPowStub::INTEGER);
3805 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003806 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003807 ASSERT(exponent_type.IsDouble());
3808 MathPowStub stub(MathPowStub::DOUBLE);
3809 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003810 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003811}
3812
3813
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003814void LCodeGen::DoRandom(LRandom* instr) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003815 class DeferredDoRandom: public LDeferredCode {
3816 public:
3817 DeferredDoRandom(LCodeGen* codegen, LRandom* instr)
3818 : LDeferredCode(codegen), instr_(instr) { }
3819 virtual void Generate() { codegen()->DoDeferredRandom(instr_); }
3820 virtual LInstruction* instr() { return instr_; }
3821 private:
3822 LRandom* instr_;
3823 };
3824
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003825 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003826 // Having marked this instruction as a call we can use any
3827 // registers.
3828 ASSERT(ToDoubleRegister(instr->result()).is(f0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003829 ASSERT(ToRegister(instr->global_object()).is(a0));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003830
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003831 static const int kSeedSize = sizeof(uint32_t);
3832 STATIC_ASSERT(kPointerSize == kSeedSize);
3833
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003834 __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003835 static const int kRandomSeedOffset =
3836 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize;
3837 __ lw(a2, FieldMemOperand(a0, kRandomSeedOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003838 // a2: FixedArray of the native context's random seeds
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003839
3840 // Load state[0].
3841 __ lw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
3842 __ Branch(deferred->entry(), eq, a1, Operand(zero_reg));
3843 // Load state[1].
3844 __ lw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
3845 // a1: state[0].
3846 // a0: state[1].
3847
3848 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16)
3849 __ And(a3, a1, Operand(0xFFFF));
3850 __ li(t0, Operand(18273));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003851 __ Mul(a3, a3, t0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003852 __ srl(a1, a1, 16);
3853 __ Addu(a1, a3, a1);
3854 // Save state[0].
3855 __ sw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize));
3856
3857 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16)
3858 __ And(a3, a0, Operand(0xFFFF));
3859 __ li(t0, Operand(36969));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00003860 __ Mul(a3, a3, t0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003861 __ srl(a0, a0, 16),
3862 __ Addu(a0, a3, a0);
3863 // Save state[1].
3864 __ sw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize));
3865
3866 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF)
3867 __ And(a0, a0, Operand(0x3FFFF));
3868 __ sll(a1, a1, 14);
3869 __ Addu(v0, a0, a1);
3870
3871 __ bind(deferred->exit());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003872
3873 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
3874 __ li(a2, Operand(0x41300000));
3875 // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
3876 __ Move(f12, v0, a2);
3877 // Move 0x4130000000000000 to FPU.
3878 __ Move(f14, zero_reg, a2);
3879 // Subtract to get the result.
3880 __ sub_d(f0, f12, f14);
3881}
3882
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00003883
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00003884void LCodeGen::DoDeferredRandom(LRandom* instr) {
3885 __ PrepareCallCFunction(1, scratch0());
3886 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
3887 // Return value is in v0.
3888}
3889
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003890
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00003891void LCodeGen::DoMathExp(LMathExp* instr) {
3892 DoubleRegister input = ToDoubleRegister(instr->value());
3893 DoubleRegister result = ToDoubleRegister(instr->result());
3894 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
3895 DoubleRegister double_scratch2 = double_scratch0();
3896 Register temp1 = ToRegister(instr->temp1());
3897 Register temp2 = ToRegister(instr->temp2());
3898
3899 MathExpGenerator::EmitMathExp(
3900 masm(), input, result, double_scratch1, double_scratch2,
3901 temp1, temp2, scratch0());
3902}
3903
3904
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003905void LCodeGen::DoMathLog(LMathLog* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003906 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3907 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3908 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003909 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003910}
3911
3912
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003913void LCodeGen::DoMathTan(LMathTan* instr) {
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00003914 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3915 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3916 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003917 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00003918}
3919
3920
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003921void LCodeGen::DoMathCos(LMathCos* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003922 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3923 TranscendentalCacheStub stub(TranscendentalCache::COS,
3924 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003925 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003926}
3927
3928
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003929void LCodeGen::DoMathSin(LMathSin* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003930 ASSERT(ToDoubleRegister(instr->result()).is(f4));
3931 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3932 TranscendentalCacheStub::UNTAGGED);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003933 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003934}
3935
3936
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003937void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3938 ASSERT(ToRegister(instr->function()).is(a1));
3939 ASSERT(instr->HasPointerMap());
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003940
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003941 Handle<JSFunction> known_function = instr->hydrogen()->known_function();
3942 if (known_function.is_null()) {
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003943 LPointerMap* pointers = instr->pointer_map();
3944 RecordPosition(pointers->position());
3945 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
3946 ParameterCount count(instr->arity());
3947 __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
3948 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3949 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00003950 CallKnownFunction(known_function,
3951 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00003952 instr->arity(),
3953 instr,
3954 CALL_AS_METHOD,
3955 A1_CONTAINS_TARGET);
3956 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003957}
3958
3959
3960void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
3961 ASSERT(ToRegister(instr->result()).is(v0));
3962
3963 int arity = instr->arity();
3964 Handle<Code> ic =
3965 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
3966 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3967 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3968}
3969
3970
3971void LCodeGen::DoCallNamed(LCallNamed* instr) {
3972 ASSERT(ToRegister(instr->result()).is(v0));
3973
3974 int arity = instr->arity();
3975 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3976 Handle<Code> ic =
3977 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
3978 __ li(a2, Operand(instr->name()));
3979 CallCode(ic, mode, instr);
3980 // Restore context register.
3981 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3982}
3983
3984
3985void LCodeGen::DoCallFunction(LCallFunction* instr) {
danno@chromium.orgc612e022011-11-10 11:38:15 +00003986 ASSERT(ToRegister(instr->function()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003987 ASSERT(ToRegister(instr->result()).is(v0));
3988
3989 int arity = instr->arity();
3990 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003991 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003992 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3993}
3994
3995
3996void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
3997 ASSERT(ToRegister(instr->result()).is(v0));
3998
3999 int arity = instr->arity();
4000 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
4001 Handle<Code> ic =
4002 isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
4003 __ li(a2, Operand(instr->name()));
4004 CallCode(ic, mode, instr);
4005 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4006}
4007
4008
4009void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
4010 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00004011 CallKnownFunction(instr->hydrogen()->target(),
4012 instr->hydrogen()->formal_parameter_count(),
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +00004013 instr->arity(),
4014 instr,
4015 CALL_AS_FUNCTION,
4016 A1_UNINITIALIZED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004017}
4018
4019
4020void LCodeGen::DoCallNew(LCallNew* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004021 ASSERT(ToRegister(instr->constructor()).is(a1));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004022 ASSERT(ToRegister(instr->result()).is(v0));
4023
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004024 __ li(a0, Operand(instr->arity()));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004025 // No cell in a2 for construct type feedback in optimized code
4026 Handle<Object> undefined_value(isolate()->factory()->undefined_value());
4027 __ li(a2, Operand(undefined_value));
ulan@chromium.org750145a2013-03-07 15:14:13 +00004028 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004029 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004030}
4031
4032
ulan@chromium.org750145a2013-03-07 15:14:13 +00004033void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
4034 ASSERT(ToRegister(instr->constructor()).is(a1));
4035 ASSERT(ToRegister(instr->result()).is(v0));
ulan@chromium.org750145a2013-03-07 15:14:13 +00004036
4037 __ li(a0, Operand(instr->arity()));
4038 __ li(a2, Operand(instr->hydrogen()->property_cell()));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004039 ElementsKind kind = instr->hydrogen()->elements_kind();
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004040 AllocationSiteOverrideMode override_mode =
danno@chromium.orgbee51992013-07-10 14:57:15 +00004041 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004042 ? DISABLE_ALLOCATION_SITES
4043 : DONT_OVERRIDE;
4044 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED;
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00004045
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004046 if (instr->arity() == 0) {
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004047 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004048 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4049 } else if (instr->arity() == 1) {
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00004050 Label done;
4051 if (IsFastPackedElementsKind(kind)) {
4052 Label packed_case;
4053 // We might need a change here,
4054 // look at the first argument.
4055 __ lw(t1, MemOperand(sp, 0));
4056 __ Branch(&packed_case, eq, t1, Operand(zero_reg));
4057
4058 ElementsKind holey_kind = GetHoleyElementsKind(kind);
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004059 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode,
4060 override_mode);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00004061 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4062 __ jmp(&done);
4063 __ bind(&packed_case);
4064 }
4065
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004066 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004067 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00004068 __ bind(&done);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004069 } else {
palfia@homejinni.com07237aa2013-07-01 08:01:48 +00004070 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004071 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
4072 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00004073}
4074
4075
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004076void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
4077 CallRuntime(instr->function(), instr->arity(), instr);
4078}
4079
4080
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00004081void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
4082 Register result = ToRegister(instr->result());
4083 Register base = ToRegister(instr->base_object());
4084 __ Addu(result, base, Operand(instr->offset()));
4085}
4086
4087
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004088void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004089 Representation representation = instr->representation();
4090
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004091 Register object = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004092 Register scratch = scratch0();
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004093 HObjectAccess access = instr->hydrogen()->access();
4094 int offset = access.offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004095
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004096 Handle<Map> transition = instr->transition();
4097
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004098 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00004099 Register value = ToRegister(instr->value());
4100 if (!instr->hydrogen()->value()->type().IsHeapObject()) {
4101 __ And(scratch, value, Operand(kSmiTagMask));
4102 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg));
4103 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004104 } else if (FLAG_track_double_fields && representation.IsDouble()) {
4105 ASSERT(transition.is_null());
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004106 ASSERT(access.IsInobject());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004107 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4108 DoubleRegister value = ToDoubleRegister(instr->value());
4109 __ sdc1(value, FieldMemOperand(object, offset));
4110 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00004111 }
4112
danno@chromium.orgf005df62013-04-30 16:36:45 +00004113 if (!transition.is_null()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00004114 __ li(scratch, Operand(transition));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004115 __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
verwaest@chromium.org37141392012-05-31 13:27:02 +00004116 if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004117 Register temp = ToRegister(instr->temp());
verwaest@chromium.org37141392012-05-31 13:27:02 +00004118 // Update the write barrier for the map field.
4119 __ RecordWriteField(object,
4120 HeapObject::kMapOffset,
4121 scratch,
4122 temp,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004123 GetRAState(),
verwaest@chromium.org37141392012-05-31 13:27:02 +00004124 kSaveFPRegs,
4125 OMIT_REMEMBERED_SET,
4126 OMIT_SMI_CHECK);
4127 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004128 }
4129
4130 // Do the store.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004131 Register value = ToRegister(instr->value());
4132 ASSERT(!object.is(value));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004133 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004134 instr->hydrogen()->value()->IsHeapObject()
4135 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004136 if (access.IsInobject()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004137 __ sw(value, FieldMemOperand(object, offset));
4138 if (instr->hydrogen()->NeedsWriteBarrier()) {
4139 // Update the write barrier for the object for in-object properties.
4140 __ RecordWriteField(object,
4141 offset,
4142 value,
4143 scratch,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004144 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004145 kSaveFPRegs,
4146 EMIT_REMEMBERED_SET,
4147 check_needed);
4148 }
4149 } else {
4150 __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
4151 __ sw(value, FieldMemOperand(scratch, offset));
4152 if (instr->hydrogen()->NeedsWriteBarrier()) {
4153 // Update the write barrier for the properties array.
4154 // object is used as a scratch register.
4155 __ RecordWriteField(scratch,
4156 offset,
4157 value,
4158 object,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004159 GetRAState(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004160 kSaveFPRegs,
4161 EMIT_REMEMBERED_SET,
4162 check_needed);
4163 }
4164 }
4165}
4166
4167
4168void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
4169 ASSERT(ToRegister(instr->object()).is(a1));
4170 ASSERT(ToRegister(instr->value()).is(a0));
4171
4172 // Name is always in a2.
4173 __ li(a2, Operand(instr->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004174 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004175 ? isolate()->builtins()->StoreIC_Initialize_Strict()
4176 : isolate()->builtins()->StoreIC_Initialize();
4177 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4178}
4179
4180
4181void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004182 if (instr->hydrogen()->skip_check()) return;
4183
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004184 if (instr->index()->IsConstantOperand()) {
4185 int constant_index =
4186 ToInteger32(LConstantOperand::cast(instr->index()));
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004187 if (instr->hydrogen()->length()->representation().IsSmi()) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004188 __ li(at, Operand(Smi::FromInt(constant_index)));
4189 } else {
4190 __ li(at, Operand(constant_index));
4191 }
4192 DeoptimizeIf(hs,
4193 instr->environment(),
4194 at,
4195 Operand(ToRegister(instr->length())));
4196 } else {
4197 DeoptimizeIf(hs,
4198 instr->environment(),
4199 ToRegister(instr->index()),
4200 Operand(ToRegister(instr->length())));
4201 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004202}
4203
4204
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004205void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
4206 Register external_pointer = ToRegister(instr->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004207 Register key = no_reg;
4208 ElementsKind elements_kind = instr->elements_kind();
4209 bool key_is_constant = instr->key()->IsConstantOperand();
4210 int constant_key = 0;
4211 if (key_is_constant) {
4212 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4213 if (constant_key & 0xF0000000) {
4214 Abort("array index constant value too big.");
4215 }
4216 } else {
4217 key = ToRegister(instr->key());
4218 }
danno@chromium.org129d3982012-07-25 15:01:47 +00004219 int element_size_shift = ElementsKindToShiftSize(elements_kind);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004220 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
danno@chromium.org129d3982012-07-25 15:01:47 +00004221 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4222 int additional_offset = instr->additional_index() << element_size_shift;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004223
4224 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
4225 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
4226 FPURegister value(ToDoubleRegister(instr->value()));
4227 if (key_is_constant) {
danno@chromium.org129d3982012-07-25 15:01:47 +00004228 __ Addu(scratch0(), external_pointer, constant_key <<
4229 element_size_shift);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004230 } else {
4231 __ sll(scratch0(), key, shift_size);
4232 __ Addu(scratch0(), scratch0(), external_pointer);
4233 }
4234
4235 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
4236 __ cvt_s_d(double_scratch0(), value);
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00004237 __ swc1(double_scratch0(), MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004238 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
jkummerow@chromium.org777db6f2012-05-24 09:33:09 +00004239 __ sdc1(value, MemOperand(scratch0(), additional_offset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004240 }
4241 } else {
4242 Register value(ToRegister(instr->value()));
danno@chromium.org129d3982012-07-25 15:01:47 +00004243 MemOperand mem_operand = PrepareKeyedOperand(
4244 key, external_pointer, key_is_constant, constant_key,
4245 element_size_shift, shift_size,
4246 instr->additional_index(), additional_offset);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004247 switch (elements_kind) {
4248 case EXTERNAL_PIXEL_ELEMENTS:
4249 case EXTERNAL_BYTE_ELEMENTS:
4250 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4251 __ sb(value, mem_operand);
4252 break;
4253 case EXTERNAL_SHORT_ELEMENTS:
4254 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4255 __ sh(value, mem_operand);
4256 break;
4257 case EXTERNAL_INT_ELEMENTS:
4258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4259 __ sw(value, mem_operand);
4260 break;
4261 case EXTERNAL_FLOAT_ELEMENTS:
4262 case EXTERNAL_DOUBLE_ELEMENTS:
4263 case FAST_DOUBLE_ELEMENTS:
4264 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004265 case FAST_SMI_ELEMENTS:
4266 case FAST_HOLEY_DOUBLE_ELEMENTS:
4267 case FAST_HOLEY_ELEMENTS:
4268 case FAST_HOLEY_SMI_ELEMENTS:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004269 case DICTIONARY_ELEMENTS:
4270 case NON_STRICT_ARGUMENTS_ELEMENTS:
4271 UNREACHABLE();
4272 break;
4273 }
4274 }
4275}
4276
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004277
4278void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) {
4279 DoubleRegister value = ToDoubleRegister(instr->value());
4280 Register elements = ToRegister(instr->elements());
4281 Register key = no_reg;
4282 Register scratch = scratch0();
4283 bool key_is_constant = instr->key()->IsConstantOperand();
4284 int constant_key = 0;
4285 Label not_nan;
4286
4287 // Calculate the effective address of the slot in the array to store the
4288 // double value.
4289 if (key_is_constant) {
4290 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
4291 if (constant_key & 0xF0000000) {
4292 Abort("array index constant value too big.");
4293 }
4294 } else {
4295 key = ToRegister(instr->key());
4296 }
4297 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004298 int shift_size = (instr->hydrogen()->key()->representation().IsSmi())
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004299 ? (element_size_shift - kSmiTagSize) : element_size_shift;
4300 if (key_is_constant) {
4301 __ Addu(scratch, elements, Operand((constant_key << element_size_shift) +
4302 FixedDoubleArray::kHeaderSize - kHeapObjectTag));
4303 } else {
4304 __ sll(scratch, key, shift_size);
4305 __ Addu(scratch, elements, Operand(scratch));
4306 __ Addu(scratch, scratch,
4307 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
4308 }
4309
4310 if (instr->NeedsCanonicalization()) {
4311 Label is_nan;
4312 // Check for NaN. All NaNs must be canonicalized.
4313 __ BranchF(NULL, &is_nan, eq, value, value);
4314 __ Branch(&not_nan);
4315
4316 // Only load canonical NaN if the comparison above set the overflow.
4317 __ bind(&is_nan);
4318 __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double());
4319 }
4320
4321 __ bind(&not_nan);
4322 __ sdc1(value, MemOperand(scratch, instr->additional_index() <<
4323 element_size_shift));
4324}
4325
4326
4327void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
4328 Register value = ToRegister(instr->value());
4329 Register elements = ToRegister(instr->elements());
4330 Register key = instr->key()->IsRegister() ? ToRegister(instr->key())
4331 : no_reg;
4332 Register scratch = scratch0();
4333 Register store_base = scratch;
4334 int offset = 0;
4335
4336 // Do the store.
4337 if (instr->key()->IsConstantOperand()) {
4338 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
4339 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
4340 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
4341 instr->additional_index());
4342 store_base = elements;
4343 } else {
4344 // Even though the HLoadKeyed instruction forces the input
4345 // representation for the key to be an integer, the input gets replaced
4346 // during bound check elimination with the index argument to the bounds
4347 // check, which can be tagged, so that case must be handled here, too.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00004348 if (instr->hydrogen()->key()->representation().IsSmi()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004349 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize);
4350 __ addu(scratch, elements, scratch);
4351 } else {
4352 __ sll(scratch, key, kPointerSizeLog2);
4353 __ addu(scratch, elements, scratch);
4354 }
4355 offset = FixedArray::OffsetOfElementAt(instr->additional_index());
4356 }
4357 __ sw(value, FieldMemOperand(store_base, offset));
4358
4359 if (instr->hydrogen()->NeedsWriteBarrier()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004360 SmiCheck check_needed =
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004361 instr->hydrogen()->value()->IsHeapObject()
4362 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004363 // Compute address of modified element and store it into key register.
4364 __ Addu(key, store_base, Operand(offset - kHeapObjectTag));
4365 __ RecordWrite(elements,
4366 key,
4367 value,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004368 GetRAState(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004369 kSaveFPRegs,
4370 EMIT_REMEMBERED_SET,
4371 check_needed);
4372 }
4373}
4374
4375
4376void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) {
4377 // By cases: external, fast double
4378 if (instr->is_external()) {
4379 DoStoreKeyedExternalArray(instr);
4380 } else if (instr->hydrogen()->value()->representation().IsDouble()) {
4381 DoStoreKeyedFixedDoubleArray(instr);
4382 } else {
4383 DoStoreKeyedFixedArray(instr);
4384 }
4385}
4386
4387
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004388void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
4389 ASSERT(ToRegister(instr->object()).is(a2));
4390 ASSERT(ToRegister(instr->key()).is(a1));
4391 ASSERT(ToRegister(instr->value()).is(a0));
4392
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004393 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004394 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
4395 : isolate()->builtins()->KeyedStoreIC_Initialize();
4396 CallCode(ic, RelocInfo::CODE_TARGET, instr);
4397}
4398
4399
4400void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
4401 Register object_reg = ToRegister(instr->object());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004402 Register scratch = scratch0();
4403
4404 Handle<Map> from_map = instr->original_map();
4405 Handle<Map> to_map = instr->transitioned_map();
yangguo@chromium.org003650e2013-01-24 16:31:08 +00004406 ElementsKind from_kind = instr->from_kind();
4407 ElementsKind to_kind = instr->to_kind();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004408
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004409 Label not_applicable;
4410 __ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4411 __ Branch(&not_applicable, ne, scratch, Operand(from_map));
4412
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00004413 if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004414 Register new_map_reg = ToRegister(instr->new_map_temp());
4415 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004416 __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset));
4417 // Write barrier.
4418 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
danno@chromium.orgc99cd482013-03-21 15:26:42 +00004419 scratch, GetRAState(), kDontSaveFPRegs);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004420 } else if (FLAG_compiled_transitions) {
4421 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4422 __ mov(a0, object_reg);
4423 __ li(a1, Operand(to_map));
4424 TransitionElementsKindStub stub(from_kind, to_kind);
4425 __ CallStub(&stub);
4426 RecordSafepointWithRegisters(
4427 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004428 } else if (IsFastSmiElementsKind(from_kind) &&
4429 IsFastDoubleElementsKind(to_kind)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004430 Register fixed_object_reg = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004431 ASSERT(fixed_object_reg.is(a2));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004432 Register new_map_reg = ToRegister(instr->new_map_temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004433 ASSERT(new_map_reg.is(a3));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004434 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004435 __ mov(fixed_object_reg, object_reg);
4436 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(),
4437 RelocInfo::CODE_TARGET, instr);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004438 } else if (IsFastDoubleElementsKind(from_kind) &&
4439 IsFastObjectElementsKind(to_kind)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004440 Register fixed_object_reg = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004441 ASSERT(fixed_object_reg.is(a2));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004442 Register new_map_reg = ToRegister(instr->new_map_temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004443 ASSERT(new_map_reg.is(a3));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004444 __ li(new_map_reg, Operand(to_map));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004445 __ mov(fixed_object_reg, object_reg);
4446 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(),
4447 RelocInfo::CODE_TARGET, instr);
4448 } else {
4449 UNREACHABLE();
4450 }
4451 __ bind(&not_applicable);
4452}
4453
4454
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004455void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
4456 Register object = ToRegister(instr->object());
4457 Register temp = ToRegister(instr->temp());
4458 Label fail;
4459 __ TestJSArrayForAllocationSiteInfo(object, temp, ne, &fail);
4460 DeoptimizeIf(al, instr->environment());
4461 __ bind(&fail);
4462}
4463
4464
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004465void LCodeGen::DoStringAdd(LStringAdd* instr) {
4466 __ push(ToRegister(instr->left()));
4467 __ push(ToRegister(instr->right()));
4468 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004469 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004470}
4471
4472
4473void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
4474 class DeferredStringCharCodeAt: public LDeferredCode {
4475 public:
4476 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
4477 : LDeferredCode(codegen), instr_(instr) { }
4478 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
4479 virtual LInstruction* instr() { return instr_; }
4480 private:
4481 LStringCharCodeAt* instr_;
4482 };
4483
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004484 DeferredStringCharCodeAt* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004485 new(zone()) DeferredStringCharCodeAt(this, instr);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00004486 StringCharLoadGenerator::Generate(masm(),
4487 ToRegister(instr->string()),
4488 ToRegister(instr->index()),
4489 ToRegister(instr->result()),
4490 deferred->entry());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004491 __ bind(deferred->exit());
4492}
4493
4494
4495void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
4496 Register string = ToRegister(instr->string());
4497 Register result = ToRegister(instr->result());
4498 Register scratch = scratch0();
4499
4500 // TODO(3095996): Get rid of this. For now, we need to make the
4501 // result register contain a valid pointer because it is already
4502 // contained in the register pointer map.
4503 __ mov(result, zero_reg);
4504
4505 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4506 __ push(string);
4507 // Push the index as a smi. This is safe because of the checks in
4508 // DoStringCharCodeAt above.
4509 if (instr->index()->IsConstantOperand()) {
4510 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
4511 __ Addu(scratch, zero_reg, Operand(Smi::FromInt(const_index)));
4512 __ push(scratch);
4513 } else {
4514 Register index = ToRegister(instr->index());
4515 __ SmiTag(index);
4516 __ push(index);
4517 }
4518 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004519 __ AssertSmi(v0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004520 __ SmiUntag(v0);
4521 __ StoreToSafepointRegisterSlot(v0, result);
4522}
4523
4524
4525void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
4526 class DeferredStringCharFromCode: public LDeferredCode {
4527 public:
4528 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
4529 : LDeferredCode(codegen), instr_(instr) { }
4530 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
4531 virtual LInstruction* instr() { return instr_; }
4532 private:
4533 LStringCharFromCode* instr_;
4534 };
4535
4536 DeferredStringCharFromCode* deferred =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004537 new(zone()) DeferredStringCharFromCode(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004538
4539 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
4540 Register char_code = ToRegister(instr->char_code());
4541 Register result = ToRegister(instr->result());
4542 Register scratch = scratch0();
4543 ASSERT(!char_code.is(result));
4544
4545 __ Branch(deferred->entry(), hi,
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004546 char_code, Operand(String::kMaxOneByteCharCode));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004547 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
4548 __ sll(scratch, char_code, kPointerSizeLog2);
4549 __ Addu(result, result, scratch);
4550 __ lw(result, FieldMemOperand(result, FixedArray::kHeaderSize));
4551 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
4552 __ Branch(deferred->entry(), eq, result, Operand(scratch));
4553 __ bind(deferred->exit());
4554}
4555
4556
4557void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
4558 Register char_code = ToRegister(instr->char_code());
4559 Register result = ToRegister(instr->result());
4560
4561 // TODO(3095996): Get rid of this. For now, we need to make the
4562 // result register contain a valid pointer because it is already
4563 // contained in the register pointer map.
4564 __ mov(result, zero_reg);
4565
4566 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4567 __ SmiTag(char_code);
4568 __ push(char_code);
4569 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
4570 __ StoreToSafepointRegisterSlot(v0, result);
4571}
4572
4573
4574void LCodeGen::DoStringLength(LStringLength* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004575 Register string = ToRegister(instr->string());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004576 Register result = ToRegister(instr->result());
4577 __ lw(result, FieldMemOperand(string, String::kLengthOffset));
4578}
4579
4580
4581void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004582 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004583 ASSERT(input->IsRegister() || input->IsStackSlot());
4584 LOperand* output = instr->result();
4585 ASSERT(output->IsDoubleRegister());
4586 FPURegister single_scratch = double_scratch0().low();
4587 if (input->IsStackSlot()) {
4588 Register scratch = scratch0();
4589 __ lw(scratch, ToMemOperand(input));
4590 __ mtc1(scratch, single_scratch);
4591 } else {
4592 __ mtc1(ToRegister(input), single_scratch);
4593 }
4594 __ cvt_d_w(ToDoubleRegister(output), single_scratch);
4595}
4596
4597
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004598void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
4599 LOperand* input = instr->value();
4600 ASSERT(input->IsRegister());
4601 LOperand* output = instr->result();
4602 ASSERT(output->IsRegister());
4603 Register scratch = scratch0();
4604
4605 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch);
4606 if (!instr->hydrogen()->value()->HasRange() ||
4607 !instr->hydrogen()->value()->range()->IsInSmiRange()) {
4608 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg));
4609 }
4610}
4611
4612
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004613void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004614 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004615 LOperand* output = instr->result();
4616
4617 FPURegister dbl_scratch = double_scratch0();
4618 __ mtc1(ToRegister(input), dbl_scratch);
4619 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22);
4620}
4621
4622
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004623void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
4624 class DeferredNumberTagI: public LDeferredCode {
4625 public:
4626 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
4627 : LDeferredCode(codegen), instr_(instr) { }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004628 virtual void Generate() {
4629 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004630 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004631 SIGNED_INT32);
4632 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004633 virtual LInstruction* instr() { return instr_; }
4634 private:
4635 LNumberTagI* instr_;
4636 };
4637
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004638 Register src = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004639 Register dst = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004640 Register overflow = scratch0();
4641
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004642 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004643 __ SmiTagCheckOverflow(dst, src, overflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004644 __ BranchOnOverflow(deferred->entry(), overflow);
4645 __ bind(deferred->exit());
4646}
4647
4648
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004649void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
4650 class DeferredNumberTagU: public LDeferredCode {
4651 public:
4652 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
4653 : LDeferredCode(codegen), instr_(instr) { }
4654 virtual void Generate() {
4655 codegen()->DoDeferredNumberTagI(instr_,
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004656 instr_->value(),
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004657 UNSIGNED_INT32);
4658 }
4659 virtual LInstruction* instr() { return instr_; }
4660 private:
4661 LNumberTagU* instr_;
4662 };
4663
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004664 LOperand* input = instr->value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004665 ASSERT(input->IsRegister() && input->Equals(instr->result()));
4666 Register reg = ToRegister(input);
4667
4668 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
4669 __ Branch(deferred->entry(), hi, reg, Operand(Smi::kMaxValue));
4670 __ SmiTag(reg, reg);
4671 __ bind(deferred->exit());
4672}
4673
4674
4675void LCodeGen::DoDeferredNumberTagI(LInstruction* instr,
4676 LOperand* value,
4677 IntegerSignedness signedness) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004678 Label slow;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004679 Register src = ToRegister(value);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004680 Register dst = ToRegister(instr->result());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004681 DoubleRegister dbl_scratch = double_scratch0();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004682
4683 // Preserve the value of all registers.
4684 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4685
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004686 Label done;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004687 if (signedness == SIGNED_INT32) {
4688 // There was overflow, so bits 30 and 31 of the original integer
4689 // disagree. Try to allocate a heap number in new space and store
4690 // the value in there. If that fails, call the runtime system.
4691 if (dst.is(src)) {
4692 __ SmiUntag(src, dst);
4693 __ Xor(src, src, Operand(0x80000000));
4694 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004695 __ mtc1(src, dbl_scratch);
4696 __ cvt_d_w(dbl_scratch, dbl_scratch);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004697 } else {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004698 __ mtc1(src, dbl_scratch);
4699 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004700 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00004701
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004702 if (FLAG_inline_new) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004703 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex);
4704 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004705 __ Move(dst, t1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004706 __ Branch(&done);
4707 }
4708
4709 // Slow case: Call the runtime system to do the number allocation.
4710 __ bind(&slow);
4711
4712 // TODO(3095996): Put a valid pointer value in the stack slot where the result
4713 // register is stored, as this register is in the pointer map, but contains an
4714 // integer value.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004715 __ StoreToSafepointRegisterSlot(zero_reg, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004716 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004717 __ Move(dst, v0);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004718 __ Subu(dst, dst, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004719
4720 // Done. Put the value in dbl_scratch into the value of the allocated heap
4721 // number.
4722 __ bind(&done);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004723 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004724 __ Addu(dst, dst, kHeapObjectTag);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004725 __ StoreToSafepointRegisterSlot(dst, dst);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004726}
4727
4728
4729void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
4730 class DeferredNumberTagD: public LDeferredCode {
4731 public:
4732 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
4733 : LDeferredCode(codegen), instr_(instr) { }
4734 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
4735 virtual LInstruction* instr() { return instr_; }
4736 private:
4737 LNumberTagD* instr_;
4738 };
4739
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004740 DoubleRegister input_reg = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004741 Register scratch = scratch0();
4742 Register reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004743 Register temp1 = ToRegister(instr->temp());
4744 Register temp2 = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004745
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004746 bool convert_hole = false;
4747 HValue* change_input = instr->hydrogen()->value();
4748 if (change_input->IsLoadKeyed()) {
4749 HLoadKeyed* load = HLoadKeyed::cast(change_input);
4750 convert_hole = load->UsesMustHandleHole();
4751 }
4752
4753 Label no_special_nan_handling;
4754 Label done;
4755 if (convert_hole) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004756 DoubleRegister input_reg = ToDoubleRegister(instr->value());
4757 __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg);
4758 __ Move(reg, scratch0(), input_reg);
4759 Label canonicalize;
4760 __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32));
4761 __ li(reg, factory()->the_hole_value());
4762 __ Branch(&done);
4763 __ bind(&canonicalize);
4764 __ Move(input_reg,
4765 FixedDoubleArray::canonical_not_the_hole_nan_as_double());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004766 }
4767
4768 __ bind(&no_special_nan_handling);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004769 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004770 if (FLAG_inline_new) {
4771 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004772 // We want the untagged address first for performance
4773 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
4774 DONT_TAG_RESULT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004775 } else {
4776 __ Branch(deferred->entry());
4777 }
4778 __ bind(deferred->exit());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00004779 __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004780 // Now that we have finished with the object's real address tag it
4781 __ Addu(reg, reg, kHeapObjectTag);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004782 __ bind(&done);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004783}
4784
4785
4786void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
4787 // TODO(3095996): Get rid of this. For now, we need to make the
4788 // result register contain a valid pointer because it is already
4789 // contained in the register pointer map.
4790 Register reg = ToRegister(instr->result());
4791 __ mov(reg, zero_reg);
4792
4793 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
4794 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004795 __ Subu(v0, v0, kHeapObjectTag);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004796 __ StoreToSafepointRegisterSlot(v0, reg);
4797}
4798
4799
4800void LCodeGen::DoSmiTag(LSmiTag* instr) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004801 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004802 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004803}
4804
4805
4806void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
4807 Register scratch = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004808 Register input = ToRegister(instr->value());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004809 Register result = ToRegister(instr->result());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004810 if (instr->needs_check()) {
4811 STATIC_ASSERT(kHeapObjectTag == 1);
4812 // If the input is a HeapObject, value of scratch won't be zero.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004813 __ And(scratch, input, Operand(kHeapObjectTag));
4814 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004815 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg));
4816 } else {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004817 __ SmiUntag(result, input);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004818 }
4819}
4820
4821
4822void LCodeGen::EmitNumberUntagD(Register input_reg,
4823 DoubleRegister result_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00004824 bool allow_undefined_as_nan,
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004825 bool deoptimize_on_minus_zero,
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004826 LEnvironment* env,
4827 NumberUntagDMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004828 Register scratch = scratch0();
4829
4830 Label load_smi, heap_number, done;
4831
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004832 STATIC_ASSERT(NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE >
4833 NUMBER_CANDIDATE_IS_ANY_TAGGED);
4834 if (mode >= NUMBER_CANDIDATE_IS_ANY_TAGGED) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004835 // Smi check.
4836 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004837
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004838 // Heap number map check.
4839 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4840 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00004841 if (!allow_undefined_as_nan) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004842 DeoptimizeIf(ne, env, scratch, Operand(at));
4843 } else {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004844 Label heap_number, convert;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004845 __ Branch(&heap_number, eq, scratch, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004846
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004847 // Convert undefined (and hole) to NaN.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004848 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004849 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE) {
4850 __ Branch(&convert, eq, input_reg, Operand(at));
4851 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
4852 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004853 DeoptimizeIf(ne, env, input_reg, Operand(at));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004854
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00004855 __ bind(&convert);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004856 __ LoadRoot(at, Heap::kNanValueRootIndex);
4857 __ ldc1(result_reg, FieldMemOperand(at, HeapNumber::kValueOffset));
4858 __ Branch(&done);
4859
4860 __ bind(&heap_number);
4861 }
4862 // Heap number to double register conversion.
4863 __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4864 if (deoptimize_on_minus_zero) {
4865 __ mfc1(at, result_reg.low());
4866 __ Branch(&done, ne, at, Operand(zero_reg));
4867 __ mfc1(scratch, result_reg.high());
4868 DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask));
4869 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004870 __ Branch(&done);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00004871 } else {
4872 __ SmiUntag(scratch, input_reg);
4873 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004874 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004875
4876 // Smi to double register conversion
4877 __ bind(&load_smi);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004878 // scratch: untagged value of input_reg
4879 __ mtc1(scratch, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004880 __ cvt_d_w(result_reg, result_reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004881 __ bind(&done);
4882}
4883
4884
4885void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004886 Register input_reg = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004887 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004888 Register scratch2 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004889 DoubleRegister double_scratch = double_scratch0();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004890 DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004891
4892 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
4893 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
4894
4895 Label done;
4896
4897 // The input is a tagged HeapObject.
4898 // Heap number map check.
4899 __ lw(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4900 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
4901 // This 'at' value and scratch1 map value are used for tests in both clauses
4902 // of the if.
4903
4904 if (instr->truncating()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004905 Register scratch3 = ToRegister(instr->temp2());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004906 FPURegister single_scratch = double_scratch.low();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004907 ASSERT(!scratch3.is(input_reg) &&
4908 !scratch3.is(scratch1) &&
4909 !scratch3.is(scratch2));
4910 // Performs a truncating conversion of a floating point number as used by
4911 // the JS bitwise operations.
4912 Label heap_number;
4913 __ Branch(&heap_number, eq, scratch1, Operand(at)); // HeapNumber map?
4914 // Check for undefined. Undefined is converted to zero for truncating
4915 // conversions.
4916 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
4917 DeoptimizeIf(ne, instr->environment(), input_reg, Operand(at));
4918 ASSERT(ToRegister(instr->result()).is(input_reg));
4919 __ mov(input_reg, zero_reg);
4920 __ Branch(&done);
4921
4922 __ bind(&heap_number);
4923 __ ldc1(double_scratch2,
4924 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4925 __ EmitECMATruncate(input_reg,
4926 double_scratch2,
4927 single_scratch,
4928 scratch1,
4929 scratch2,
4930 scratch3);
4931 } else {
4932 // Deoptimize if we don't have a heap number.
4933 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at));
4934
4935 // Load the double value.
4936 __ ldc1(double_scratch,
4937 FieldMemOperand(input_reg, HeapNumber::kValueOffset));
4938
4939 Register except_flag = scratch2;
4940 __ EmitFPUTruncate(kRoundToZero,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004941 input_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004942 double_scratch,
4943 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004944 double_scratch2,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004945 except_flag,
4946 kCheckForInexactConversion);
4947
4948 // Deopt if the operation did not succeed.
4949 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
4950
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004951 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
4952 __ Branch(&done, ne, input_reg, Operand(zero_reg));
4953
4954 __ mfc1(scratch1, double_scratch.high());
4955 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
4956 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
4957 }
4958 }
4959 __ bind(&done);
4960}
4961
4962
4963void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
4964 class DeferredTaggedToI: public LDeferredCode {
4965 public:
4966 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
4967 : LDeferredCode(codegen), instr_(instr) { }
4968 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
4969 virtual LInstruction* instr() { return instr_; }
4970 private:
4971 LTaggedToI* instr_;
4972 };
4973
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004974 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004975 ASSERT(input->IsRegister());
4976 ASSERT(input->Equals(instr->result()));
4977
4978 Register input_reg = ToRegister(input);
4979
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004980 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004981
4982 // Let the deferred code handle the HeapObject case.
4983 __ JumpIfNotSmi(input_reg, deferred->entry());
4984
4985 // Smi to int32 conversion.
4986 __ SmiUntag(input_reg);
4987 __ bind(deferred->exit());
4988}
4989
4990
4991void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004992 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004993 ASSERT(input->IsRegister());
4994 LOperand* result = instr->result();
4995 ASSERT(result->IsDoubleRegister());
4996
4997 Register input_reg = ToRegister(input);
4998 DoubleRegister result_reg = ToDoubleRegister(result);
4999
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005000 NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED;
5001 HValue* value = instr->hydrogen()->value();
5002 if (value->type().IsSmi()) {
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +00005003 mode = NUMBER_CANDIDATE_IS_SMI;
5004 } else if (value->IsLoadKeyed()) {
5005 HLoadKeyed* load = HLoadKeyed::cast(value);
5006 if (load->UsesMustHandleHole()) {
5007 if (load->hole_mode() == ALLOW_RETURN_HOLE) {
5008 mode = NUMBER_CANDIDATE_IS_ANY_TAGGED_CONVERT_HOLE;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005009 }
5010 }
5011 }
5012
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005013 EmitNumberUntagD(input_reg, result_reg,
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005014 instr->hydrogen()->allow_undefined_as_nan(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005015 instr->hydrogen()->deoptimize_on_minus_zero(),
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005016 instr->environment(),
5017 mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005018}
5019
5020
5021void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
5022 Register result_reg = ToRegister(instr->result());
5023 Register scratch1 = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005024 Register scratch2 = ToRegister(instr->temp());
5025 DoubleRegister double_input = ToDoubleRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005026
5027 if (instr->truncating()) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005028 Register scratch3 = ToRegister(instr->temp2());
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005029 FPURegister single_scratch = double_scratch0().low();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005030 __ EmitECMATruncate(result_reg,
5031 double_input,
5032 single_scratch,
5033 scratch1,
5034 scratch2,
5035 scratch3);
5036 } else {
5037 Register except_flag = scratch2;
5038
5039 __ EmitFPUTruncate(kRoundToMinusInf,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005040 result_reg,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005041 double_input,
5042 scratch1,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005043 double_scratch0(),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005044 except_flag,
5045 kCheckForInexactConversion);
5046
5047 // Deopt if the operation did not succeed (except_flag != 0).
5048 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005049
5050 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5051 Label done;
5052 __ Branch(&done, ne, result_reg, Operand(zero_reg));
5053 __ mfc1(scratch1, double_input.high());
5054 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
5055 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
5056 __ bind(&done);
5057 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005058 }
5059}
5060
5061
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005062void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
5063 Register result_reg = ToRegister(instr->result());
5064 Register scratch1 = scratch0();
5065 Register scratch2 = ToRegister(instr->temp());
5066 DoubleRegister double_input = ToDoubleRegister(instr->value());
5067
5068 if (instr->truncating()) {
5069 Register scratch3 = ToRegister(instr->temp2());
5070 FPURegister single_scratch = double_scratch0().low();
5071 __ EmitECMATruncate(result_reg,
5072 double_input,
5073 single_scratch,
5074 scratch1,
5075 scratch2,
5076 scratch3);
5077 } else {
5078 Register except_flag = scratch2;
5079
5080 __ EmitFPUTruncate(kRoundToMinusInf,
5081 result_reg,
5082 double_input,
5083 scratch1,
5084 double_scratch0(),
5085 except_flag,
5086 kCheckForInexactConversion);
5087
5088 // Deopt if the operation did not succeed (except_flag != 0).
5089 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
5090
5091 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
5092 Label done;
5093 __ Branch(&done, ne, result_reg, Operand(zero_reg));
5094 __ mfc1(scratch1, double_input.high());
5095 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask));
5096 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg));
5097 __ bind(&done);
5098 }
5099 }
5100 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1);
5101 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg));
5102}
5103
5104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005105void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005106 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005107 __ And(at, ToRegister(input), Operand(kSmiTagMask));
5108 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg));
5109}
5110
5111
5112void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005113 if (!instr->hydrogen()->value()->IsHeapObject()) {
5114 LOperand* input = instr->value();
5115 __ And(at, ToRegister(input), Operand(kSmiTagMask));
5116 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5117 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005118}
5119
5120
5121void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005122 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005123 Register scratch = scratch0();
5124
5125 __ GetObjectType(input, scratch, scratch);
5126
5127 if (instr->hydrogen()->is_interval_check()) {
5128 InstanceType first;
5129 InstanceType last;
5130 instr->hydrogen()->GetCheckInterval(&first, &last);
5131
5132 // If there is only one type in the interval check for equality.
5133 if (first == last) {
5134 DeoptimizeIf(ne, instr->environment(), scratch, Operand(first));
5135 } else {
5136 DeoptimizeIf(lo, instr->environment(), scratch, Operand(first));
5137 // Omit check for the last type.
5138 if (last != LAST_TYPE) {
5139 DeoptimizeIf(hi, instr->environment(), scratch, Operand(last));
5140 }
5141 }
5142 } else {
5143 uint8_t mask;
5144 uint8_t tag;
5145 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
5146
5147 if (IsPowerOf2(mask)) {
5148 ASSERT(tag == 0 || IsPowerOf2(tag));
5149 __ And(at, scratch, mask);
5150 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment(),
5151 at, Operand(zero_reg));
5152 } else {
5153 __ And(scratch, scratch, Operand(mask));
5154 DeoptimizeIf(ne, instr->environment(), scratch, Operand(tag));
5155 }
5156 }
5157}
5158
5159
5160void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005161 Register reg = ToRegister(instr->value());
5162 Handle<JSFunction> target = instr->hydrogen()->target();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005163 AllowDeferredHandleDereference smi_check;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005164 if (isolate()->heap()->InNewSpace(*target)) {
5165 Register reg = ToRegister(instr->value());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00005166 Handle<Cell> cell = isolate()->factory()->NewPropertyCell(target);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005167 __ li(at, Operand(Handle<Object>(cell)));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00005168 __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005169 DeoptimizeIf(ne, instr->environment(), reg,
5170 Operand(at));
5171 } else {
5172 DeoptimizeIf(ne, instr->environment(), reg,
5173 Operand(target));
5174 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005175}
5176
5177
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005178void LCodeGen::DoCheckMapCommon(Register map_reg,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005179 Handle<Map> map,
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005180 LEnvironment* env) {
5181 Label success;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005182 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00005183 DeoptimizeIf(al, env);
5184 __ bind(&success);
5185}
5186
5187
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005188void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005189 Register map_reg = scratch0();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005190 LOperand* input = instr->value();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005191 ASSERT(input->IsRegister());
5192 Register reg = ToRegister(input);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005193 Label success;
5194 SmallMapList* map_set = instr->hydrogen()->map_set();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005195 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005196 for (int i = 0; i < map_set->length() - 1; i++) {
5197 Handle<Map> map = map_set->at(i);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005198 __ CompareMapAndBranch(map_reg, map, &success, eq, &success);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005199 }
5200 Handle<Map> map = map_set->last();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005201 DoCheckMapCommon(map_reg, map, instr->environment());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00005202 __ bind(&success);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005203}
5204
5205
5206void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
5207 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
5208 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005209 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005210 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
5211}
5212
5213
5214void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
5215 Register unclamped_reg = ToRegister(instr->unclamped());
5216 Register result_reg = ToRegister(instr->result());
5217 __ ClampUint8(result_reg, unclamped_reg);
5218}
5219
5220
5221void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
5222 Register scratch = scratch0();
5223 Register input_reg = ToRegister(instr->unclamped());
5224 Register result_reg = ToRegister(instr->result());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005225 DoubleRegister temp_reg = ToDoubleRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005226 Label is_smi, done, heap_number;
5227
5228 // Both smi and heap number cases are handled.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00005229 __ UntagAndJumpIfSmi(scratch, input_reg, &is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005230
5231 // Check for heap number
5232 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
5233 __ Branch(&heap_number, eq, scratch, Operand(factory()->heap_number_map()));
5234
5235 // Check for undefined. Undefined is converted to zero for clamping
5236 // conversions.
5237 DeoptimizeIf(ne, instr->environment(), input_reg,
5238 Operand(factory()->undefined_value()));
5239 __ mov(result_reg, zero_reg);
5240 __ jmp(&done);
5241
5242 // Heap number
5243 __ bind(&heap_number);
5244 __ ldc1(double_scratch0(), FieldMemOperand(input_reg,
5245 HeapNumber::kValueOffset));
5246 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
5247 __ jmp(&done);
5248
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005249 __ bind(&is_smi);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005250 __ ClampUint8(result_reg, scratch);
5251
5252 __ bind(&done);
5253}
5254
5255
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005256void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005257 Register prototype_reg = ToRegister(instr->temp());
5258 Register map_reg = ToRegister(instr->temp2());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005259
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005260 ZoneList<Handle<JSObject> >* prototypes = instr->prototypes();
5261 ZoneList<Handle<Map> >* maps = instr->maps();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005262
yangguo@chromium.org003650e2013-01-24 16:31:08 +00005263 ASSERT(prototypes->length() == maps->length());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005264
danno@chromium.org41728482013-06-12 22:31:22 +00005265 if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005266 for (int i = 0; i < prototypes->length(); i++) {
5267 __ LoadHeapObject(prototype_reg, prototypes->at(i));
5268 __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005269 DoCheckMapCommon(map_reg, maps->at(i), instr->environment());
ulan@chromium.org2e04b582013-02-21 14:06:02 +00005270 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005271 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005272}
5273
5274
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005275void LCodeGen::DoAllocate(LAllocate* instr) {
5276 class DeferredAllocate: public LDeferredCode {
5277 public:
5278 DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
5279 : LDeferredCode(codegen), instr_(instr) { }
5280 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
5281 virtual LInstruction* instr() { return instr_; }
5282 private:
5283 LAllocate* instr_;
5284 };
5285
5286 DeferredAllocate* deferred =
5287 new(zone()) DeferredAllocate(this, instr);
5288
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005289 Register result = ToRegister(instr->result());
5290 Register scratch = ToRegister(instr->temp1());
5291 Register scratch2 = ToRegister(instr->temp2());
5292
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005293 // Allocate memory for the object.
5294 AllocationFlags flags = TAG_OBJECT;
5295 if (instr->hydrogen()->MustAllocateDoubleAligned()) {
5296 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
5297 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005298 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005299 ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005300 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005301 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
5302 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005303 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005304 if (instr->size()->IsConstantOperand()) {
5305 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005306 __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005307 } else {
5308 Register size = ToRegister(instr->size());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005309 __ Allocate(size,
5310 result,
5311 scratch,
5312 scratch2,
5313 deferred->entry(),
5314 flags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005315 }
5316
5317 __ bind(deferred->exit());
5318}
5319
5320
5321void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005322 Register result = ToRegister(instr->result());
5323
5324 // TODO(3095996): Get rid of this. For now, we need to make the
5325 // result register contain a valid pointer because it is already
5326 // contained in the register pointer map.
5327 __ mov(result, zero_reg);
5328
5329 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
danno@chromium.orgf005df62013-04-30 16:36:45 +00005330 if (instr->size()->IsRegister()) {
5331 Register size = ToRegister(instr->size());
5332 ASSERT(!size.is(result));
5333 __ SmiTag(size);
5334 __ push(size);
5335 } else {
5336 int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
5337 __ Push(Smi::FromInt(size));
5338 }
5339
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005340 if (instr->hydrogen()->CanAllocateInOldPointerSpace()) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005341 ASSERT(!instr->hydrogen()->CanAllocateInOldDataSpace());
5342 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr);
5343 } else if (instr->hydrogen()->CanAllocateInOldDataSpace()) {
5344 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005345 } else {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00005346 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00005347 }
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00005348 __ StoreToSafepointRegisterSlot(v0, result);
5349}
5350
5351
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005352void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005353 ASSERT(ToRegister(instr->value()).is(a0));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005354 ASSERT(ToRegister(instr->result()).is(v0));
5355 __ push(a0);
5356 CallRuntime(Runtime::kToFastProperties, 1, instr);
5357}
5358
5359
5360void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
5361 Label materialized;
5362 // Registers will be used as follows:
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005363 // t3 = literals array.
5364 // a1 = regexp literal.
5365 // a0 = regexp literal clone.
5366 // a2 and t0-t2 are used as temporaries.
yangguo@chromium.org9c741c82012-06-28 15:04:22 +00005367 int literal_offset =
5368 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
5369 __ LoadHeapObject(t3, instr->hydrogen()->literals());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005370 __ lw(a1, FieldMemOperand(t3, literal_offset));
5371 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5372 __ Branch(&materialized, ne, a1, Operand(at));
5373
5374 // Create regexp literal using runtime function
5375 // Result will be in v0.
5376 __ li(t2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
5377 __ li(t1, Operand(instr->hydrogen()->pattern()));
5378 __ li(t0, Operand(instr->hydrogen()->flags()));
5379 __ Push(t3, t2, t1, t0);
5380 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
5381 __ mov(a1, v0);
5382
5383 __ bind(&materialized);
5384 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
5385 Label allocated, runtime_allocate;
5386
jkummerow@chromium.org4c54a2a2013-03-19 17:51:30 +00005387 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005388 __ jmp(&allocated);
5389
5390 __ bind(&runtime_allocate);
5391 __ li(a0, Operand(Smi::FromInt(size)));
5392 __ Push(a1, a0);
5393 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
5394 __ pop(a1);
5395
5396 __ bind(&allocated);
5397 // Copy the content into the newly allocated memory.
5398 // (Unroll copy loop once for better throughput).
5399 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
5400 __ lw(a3, FieldMemOperand(a1, i));
5401 __ lw(a2, FieldMemOperand(a1, i + kPointerSize));
5402 __ sw(a3, FieldMemOperand(v0, i));
5403 __ sw(a2, FieldMemOperand(v0, i + kPointerSize));
5404 }
5405 if ((size % (2 * kPointerSize)) != 0) {
5406 __ lw(a3, FieldMemOperand(a1, size - kPointerSize));
5407 __ sw(a3, FieldMemOperand(v0, size - kPointerSize));
5408 }
5409}
5410
5411
5412void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
5413 // Use the fast case closure allocation code that allocates in new
5414 // space for nested functions that don't need literals cloning.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005415 bool pretenure = instr->hydrogen()->pretenure();
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005416 if (!pretenure && instr->hydrogen()->has_no_literals()) {
5417 FastNewClosureStub stub(instr->hydrogen()->language_mode(),
5418 instr->hydrogen()->is_generator());
5419 __ li(a1, Operand(instr->hydrogen()->shared_info()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005420 __ push(a1);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005421 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005422 } else {
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005423 __ li(a2, Operand(instr->hydrogen()->shared_info()));
5424 __ li(a1, Operand(pretenure ? factory()->true_value()
5425 : factory()->false_value()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005426 __ Push(cp, a2, a1);
5427 CallRuntime(Runtime::kNewClosure, 3, instr);
5428 }
5429}
5430
5431
5432void LCodeGen::DoTypeof(LTypeof* instr) {
5433 ASSERT(ToRegister(instr->result()).is(v0));
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005434 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005435 __ push(input);
5436 CallRuntime(Runtime::kTypeof, 1, instr);
5437}
5438
5439
5440void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005441 Register input = ToRegister(instr->value());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005442
5443 Register cmp1 = no_reg;
5444 Operand cmp2 = Operand(no_reg);
5445
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005446 Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_),
5447 instr->FalseLabel(chunk_),
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005448 input,
5449 instr->type_literal(),
5450 cmp1,
5451 cmp2);
5452
5453 ASSERT(cmp1.is_valid());
5454 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid());
5455
5456 if (final_branch_condition != kNoCondition) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005457 EmitBranch(instr, final_branch_condition, cmp1, cmp2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005458 }
5459}
5460
5461
5462Condition LCodeGen::EmitTypeofIs(Label* true_label,
5463 Label* false_label,
5464 Register input,
5465 Handle<String> type_name,
5466 Register& cmp1,
5467 Operand& cmp2) {
5468 // This function utilizes the delay slot heavily. This is used to load
5469 // values that are always usable without depending on the type of the input
5470 // register.
5471 Condition final_branch_condition = kNoCondition;
5472 Register scratch = scratch0();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005473 if (type_name->Equals(heap()->number_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005474 __ JumpIfSmi(input, true_label);
5475 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5476 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
5477 cmp1 = input;
5478 cmp2 = Operand(at);
5479 final_branch_condition = eq;
5480
ulan@chromium.org750145a2013-03-07 15:14:13 +00005481 } else if (type_name->Equals(heap()->string_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005482 __ JumpIfSmi(input, false_label);
5483 __ GetObjectType(input, input, scratch);
5484 __ Branch(USE_DELAY_SLOT, false_label,
5485 ge, scratch, Operand(FIRST_NONSTRING_TYPE));
5486 // input is an object so we can load the BitFieldOffset even if we take the
5487 // other branch.
5488 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5489 __ And(at, at, 1 << Map::kIsUndetectable);
5490 cmp1 = at;
5491 cmp2 = Operand(zero_reg);
5492 final_branch_condition = eq;
5493
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005494 } else if (type_name->Equals(heap()->symbol_string())) {
5495 __ JumpIfSmi(input, false_label);
5496 __ GetObjectType(input, input, scratch);
5497 cmp1 = scratch;
5498 cmp2 = Operand(SYMBOL_TYPE);
5499 final_branch_condition = eq;
5500
ulan@chromium.org750145a2013-03-07 15:14:13 +00005501 } else if (type_name->Equals(heap()->boolean_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005502 __ LoadRoot(at, Heap::kTrueValueRootIndex);
5503 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5504 __ LoadRoot(at, Heap::kFalseValueRootIndex);
5505 cmp1 = at;
5506 cmp2 = Operand(input);
5507 final_branch_condition = eq;
5508
ulan@chromium.org750145a2013-03-07 15:14:13 +00005509 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005510 __ LoadRoot(at, Heap::kNullValueRootIndex);
5511 cmp1 = at;
5512 cmp2 = Operand(input);
5513 final_branch_condition = eq;
5514
ulan@chromium.org750145a2013-03-07 15:14:13 +00005515 } else if (type_name->Equals(heap()->undefined_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005516 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5517 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5518 // The first instruction of JumpIfSmi is an And - it is safe in the delay
5519 // slot.
5520 __ JumpIfSmi(input, false_label);
5521 // Check for undetectable objects => true.
5522 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset));
5523 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset));
5524 __ And(at, at, 1 << Map::kIsUndetectable);
5525 cmp1 = at;
5526 cmp2 = Operand(zero_reg);
5527 final_branch_condition = ne;
5528
ulan@chromium.org750145a2013-03-07 15:14:13 +00005529 } else if (type_name->Equals(heap()->function_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005530 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
5531 __ JumpIfSmi(input, false_label);
5532 __ GetObjectType(input, scratch, input);
5533 __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE));
5534 cmp1 = input;
5535 cmp2 = Operand(JS_FUNCTION_PROXY_TYPE);
5536 final_branch_condition = eq;
5537
ulan@chromium.org750145a2013-03-07 15:14:13 +00005538 } else if (type_name->Equals(heap()->object_string())) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005539 __ JumpIfSmi(input, false_label);
5540 if (!FLAG_harmony_typeof) {
5541 __ LoadRoot(at, Heap::kNullValueRootIndex);
5542 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input));
5543 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005544 Register map = input;
5545 __ GetObjectType(input, map, scratch);
5546 __ Branch(false_label,
5547 lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005548 __ Branch(USE_DELAY_SLOT, false_label,
5549 gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005550 // map is still valid, so the BitField can be loaded in delay slot.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005551 // Check for undetectable objects => false.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005552 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005553 __ And(at, at, 1 << Map::kIsUndetectable);
5554 cmp1 = at;
5555 cmp2 = Operand(zero_reg);
5556 final_branch_condition = eq;
5557
5558 } else {
5559 cmp1 = at;
5560 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion.
5561 __ Branch(false_label);
5562 }
5563
5564 return final_branch_condition;
5565}
5566
5567
5568void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00005569 Register temp1 = ToRegister(instr->temp());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005570
5571 EmitIsConstructCall(temp1, scratch0());
5572
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005573 EmitBranch(instr, eq, temp1,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005574 Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
5575}
5576
5577
5578void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
5579 ASSERT(!temp1.is(temp2));
5580 // Get the frame pointer for the calling frame.
5581 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5582
5583 // Skip the arguments adaptor frame if it exists.
5584 Label check_frame_marker;
5585 __ lw(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
5586 __ Branch(&check_frame_marker, ne, temp2,
5587 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
5588 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
5589
5590 // Check the marker in the calling frame.
5591 __ bind(&check_frame_marker);
5592 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
5593}
5594
5595
erikcorry0ad885c2011-11-21 13:51:57 +00005596void LCodeGen::EnsureSpaceForLazyDeopt() {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00005597 if (info()->IsStub()) return;
erikcorry0ad885c2011-11-21 13:51:57 +00005598 // Ensure that we have enough space after the previous lazy-bailout
5599 // instruction for patching the code here.
5600 int current_pc = masm()->pc_offset();
5601 int patch_size = Deoptimizer::patch_size();
5602 if (current_pc < last_lazy_deopt_pc_ + patch_size) {
5603 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
5604 ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
5605 while (padding_size > 0) {
5606 __ nop();
5607 padding_size -= Assembler::kInstrSize;
5608 }
5609 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005610 last_lazy_deopt_pc_ = masm()->pc_offset();
erikcorry0ad885c2011-11-21 13:51:57 +00005611}
5612
5613
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005614void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005615 EnsureSpaceForLazyDeopt();
5616 ASSERT(instr->HasEnvironment());
5617 LEnvironment* env = instr->environment();
5618 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5619 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005620}
5621
5622
5623void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
palfia@homejinni.com04109732013-05-15 09:50:32 +00005624 if (instr->hydrogen_value()->IsSoftDeoptimize()) {
5625 SoftDeoptimize(instr->environment(), zero_reg, Operand(zero_reg));
5626 } else {
5627 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg));
5628 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005629}
5630
5631
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00005632void LCodeGen::DoDummyUse(LDummyUse* instr) {
5633 // Nothing to see here, move on!
5634}
5635
5636
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005637void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
erikcorry0ad885c2011-11-21 13:51:57 +00005638 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
5639 __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
5640 RecordSafepointWithLazyDeopt(
5641 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
5642 ASSERT(instr->HasEnvironment());
5643 LEnvironment* env = instr->environment();
5644 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005645}
5646
5647
5648void LCodeGen::DoStackCheck(LStackCheck* instr) {
5649 class DeferredStackCheck: public LDeferredCode {
5650 public:
5651 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
5652 : LDeferredCode(codegen), instr_(instr) { }
5653 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
5654 virtual LInstruction* instr() { return instr_; }
5655 private:
5656 LStackCheck* instr_;
5657 };
5658
erikcorry0ad885c2011-11-21 13:51:57 +00005659 ASSERT(instr->HasEnvironment());
5660 LEnvironment* env = instr->environment();
5661 // There is no LLazyBailout instruction for stack-checks. We have to
5662 // prepare for lazy deoptimization explicitly here.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005663 if (instr->hydrogen()->is_function_entry()) {
5664 // Perform stack overflow check.
5665 Label done;
5666 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5667 __ Branch(&done, hs, sp, Operand(at));
5668 StackCheckStub stub;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00005669 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
erikcorry0ad885c2011-11-21 13:51:57 +00005670 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005671 __ bind(&done);
erikcorry0ad885c2011-11-21 13:51:57 +00005672 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5673 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005674 } else {
5675 ASSERT(instr->hydrogen()->is_backwards_branch());
5676 // Perform stack overflow check if this goto needs it before jumping.
5677 DeferredStackCheck* deferred_stack_check =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00005678 new(zone()) DeferredStackCheck(this, instr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005679 __ LoadRoot(at, Heap::kStackLimitRootIndex);
5680 __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at));
erikcorry0ad885c2011-11-21 13:51:57 +00005681 EnsureSpaceForLazyDeopt();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005682 __ bind(instr->done_label());
5683 deferred_stack_check->SetExit(instr->done_label());
erikcorry0ad885c2011-11-21 13:51:57 +00005684 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
5685 // Don't record a deoptimization index for the safepoint here.
5686 // This will be done explicitly when emitting call and the safepoint in
5687 // the deferred code.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005688 }
5689}
5690
5691
5692void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
5693 // This is a pseudo-instruction that ensures that the environment here is
5694 // properly registered for deoptimization and records the assembler's PC
5695 // offset.
5696 LEnvironment* environment = instr->environment();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005697
5698 // If the environment were already registered, we would have no way of
5699 // backpatching it with the spill slot operands.
5700 ASSERT(!environment->HasBeenRegistered());
erikcorry0ad885c2011-11-21 13:51:57 +00005701 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005702
5703 // Normally we record the first unknown OSR value as the entrypoint to the OSR
5704 // code, but if there were none, record the entrypoint here.
5705 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005706}
5707
5708
ulan@chromium.org812308e2012-02-29 15:58:45 +00005709void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
5710 Register result = ToRegister(instr->result());
5711 Register object = ToRegister(instr->object());
5712 __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
5713 DeoptimizeIf(eq, instr->environment(), object, Operand(at));
5714
5715 Register null_value = t1;
5716 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
5717 DeoptimizeIf(eq, instr->environment(), object, Operand(null_value));
5718
5719 __ And(at, object, kSmiTagMask);
5720 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg));
5721
5722 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
5723 __ GetObjectType(object, a1, a1);
5724 DeoptimizeIf(le, instr->environment(), a1, Operand(LAST_JS_PROXY_TYPE));
5725
5726 Label use_cache, call_runtime;
5727 ASSERT(object.is(a0));
5728 __ CheckEnumCache(null_value, &call_runtime);
5729
5730 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset));
5731 __ Branch(&use_cache);
5732
5733 // Get the set of properties to enumerate.
5734 __ bind(&call_runtime);
5735 __ push(object);
5736 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
5737
5738 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
5739 ASSERT(result.is(v0));
5740 __ LoadRoot(at, Heap::kMetaMapRootIndex);
5741 DeoptimizeIf(ne, instr->environment(), a1, Operand(at));
5742 __ bind(&use_cache);
5743}
5744
5745
5746void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
5747 Register map = ToRegister(instr->map());
5748 Register result = ToRegister(instr->result());
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005749 Label load_cache, done;
5750 __ EnumLength(result, map);
5751 __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0)));
5752 __ li(result, Operand(isolate()->factory()->empty_fixed_array()));
5753 __ jmp(&done);
5754
5755 __ bind(&load_cache);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005756 __ LoadInstanceDescriptors(map, result);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005757 __ lw(result,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005758 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
ulan@chromium.org812308e2012-02-29 15:58:45 +00005759 __ lw(result,
5760 FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
5761 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg));
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00005762
5763 __ bind(&done);
ulan@chromium.org812308e2012-02-29 15:58:45 +00005764}
5765
5766
5767void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
5768 Register object = ToRegister(instr->value());
5769 Register map = ToRegister(instr->map());
5770 __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset));
5771 DeoptimizeIf(ne, instr->environment(), map, Operand(scratch0()));
5772}
5773
5774
5775void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
5776 Register object = ToRegister(instr->object());
5777 Register index = ToRegister(instr->index());
5778 Register result = ToRegister(instr->result());
5779 Register scratch = scratch0();
5780
5781 Label out_of_object, done;
5782 __ Branch(USE_DELAY_SLOT, &out_of_object, lt, index, Operand(zero_reg));
5783 __ sll(scratch, index, kPointerSizeLog2 - kSmiTagSize); // In delay slot.
5784
5785 STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
5786 __ Addu(scratch, object, scratch);
5787 __ lw(result, FieldMemOperand(scratch, JSObject::kHeaderSize));
5788
5789 __ Branch(&done);
5790
5791 __ bind(&out_of_object);
5792 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
5793 // Index is equal to negated out of object property index plus 1.
5794 __ Subu(scratch, result, scratch);
5795 __ lw(result, FieldMemOperand(scratch,
5796 FixedArray::kHeaderSize - kPointerSize));
5797 __ bind(&done);
5798}
5799
5800
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005801#undef __
5802
5803} } // namespace v8::internal