blob: b73b82f1dde7849f665a5ff69cf982ccb99cf647 [file] [log] [blame]
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000028#include "v8.h"
29
kasperl@chromium.orga5551262010-12-07 12:49:48 +000030#include "arm/lithium-codegen-arm.h"
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000031#include "arm/lithium-gap-resolver-arm.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000032#include "code-stubs.h"
33#include "stub-cache.h"
34
35namespace v8 {
36namespace internal {
37
38
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000039class SafepointGenerator : public CallWrapper {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000040 public:
41 SafepointGenerator(LCodeGen* codegen,
42 LPointerMap* pointers,
43 int deoptimization_index)
44 : codegen_(codegen),
45 pointers_(pointers),
46 deoptimization_index_(deoptimization_index) { }
47 virtual ~SafepointGenerator() { }
48
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000049 virtual void BeforeCall(int call_size) const {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000050 ASSERT(call_size >= 0);
51 // Ensure that we have enough space after the previous safepoint position
52 // for the generated code there.
53 int call_end = codegen_->masm()->pc_offset() + call_size;
54 int prev_jump_end =
55 codegen_->LastSafepointEnd() + Deoptimizer::patch_size();
56 if (call_end < prev_jump_end) {
57 int padding_size = prev_jump_end - call_end;
58 ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
59 while (padding_size > 0) {
60 codegen_->masm()->nop();
61 padding_size -= Assembler::kInstrSize;
62 }
63 }
64 }
65
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000066 virtual void AfterCall() const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000067 codegen_->RecordSafepoint(pointers_, deoptimization_index_);
68 }
69
70 private:
71 LCodeGen* codegen_;
72 LPointerMap* pointers_;
73 int deoptimization_index_;
74};
75
76
77#define __ masm()->
78
79bool LCodeGen::GenerateCode() {
80 HPhase phase("Code generation", chunk());
81 ASSERT(is_unused());
82 status_ = GENERATING;
83 CpuFeatures::Scope scope1(VFP3);
84 CpuFeatures::Scope scope2(ARMv7);
85 return GeneratePrologue() &&
86 GenerateBody() &&
87 GenerateDeferredCode() &&
danno@chromium.org40cb8782011-05-25 07:58:50 +000088 GenerateDeoptJumpTable() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +000089 GenerateSafepointTable();
90}
91
92
93void LCodeGen::FinishCode(Handle<Code> code) {
94 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +000095 code->set_stack_slots(GetStackSlotCount());
ricow@chromium.org83aa5492011-02-07 12:42:56 +000096 code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000097 PopulateDeoptimizationData(code);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000098 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000099}
100
101
102void LCodeGen::Abort(const char* format, ...) {
103 if (FLAG_trace_bailout) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000104 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
105 PrintF("Aborting LCodeGen in @\"%s\": ", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000106 va_list arguments;
107 va_start(arguments, format);
108 OS::VPrint(format, arguments);
109 va_end(arguments);
110 PrintF("\n");
111 }
112 status_ = ABORTED;
113}
114
115
116void LCodeGen::Comment(const char* format, ...) {
117 if (!FLAG_code_comments) return;
118 char buffer[4 * KB];
119 StringBuilder builder(buffer, ARRAY_SIZE(buffer));
120 va_list arguments;
121 va_start(arguments, format);
122 builder.AddFormattedList(format, arguments);
123 va_end(arguments);
124
125 // Copy the string before recording it in the assembler to avoid
126 // issues when the stack allocated buffer goes out of scope.
127 size_t length = builder.position();
128 Vector<char> copy = Vector<char>::New(length + 1);
129 memcpy(copy.start(), builder.Finalize(), copy.length());
130 masm()->RecordComment(copy.start());
131}
132
133
134bool LCodeGen::GeneratePrologue() {
135 ASSERT(is_generating());
136
137#ifdef DEBUG
138 if (strlen(FLAG_stop_at) > 0 &&
139 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
140 __ stop("stop_at");
141 }
142#endif
143
144 // r1: Callee's JS function.
145 // cp: Callee's context.
146 // fp: Caller's frame pointer.
147 // lr: Caller's pc.
148
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000149 // Strict mode functions and builtins need to replace the receiver
150 // with undefined when called as functions (without an explicit
151 // receiver object). r5 is zero for method calls and non-zero for
152 // function calls.
153 if (info_->is_strict_mode() || info_->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000154 Label ok;
155 __ cmp(r5, Operand(0));
156 __ b(eq, &ok);
157 int receiver_offset = scope()->num_parameters() * kPointerSize;
158 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
159 __ str(r2, MemOperand(sp, receiver_offset));
160 __ bind(&ok);
161 }
162
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000163 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
164 __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP.
165
166 // Reserve space for the stack slots needed by the code.
danno@chromium.org160a7b02011-04-18 15:51:38 +0000167 int slots = GetStackSlotCount();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000168 if (slots > 0) {
169 if (FLAG_debug_code) {
170 __ mov(r0, Operand(slots));
171 __ mov(r2, Operand(kSlotsZapValue));
172 Label loop;
173 __ bind(&loop);
174 __ push(r2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000175 __ sub(r0, r0, Operand(1), SetCC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000176 __ b(ne, &loop);
177 } else {
178 __ sub(sp, sp, Operand(slots * kPointerSize));
179 }
180 }
181
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000182 // Possibly allocate a local context.
183 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
184 if (heap_slots > 0) {
185 Comment(";;; Allocate local context");
186 // Argument to NewContext is the function, which is in r1.
187 __ push(r1);
188 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
189 FastNewContextStub stub(heap_slots);
190 __ CallStub(&stub);
191 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000192 __ CallRuntime(Runtime::kNewFunctionContext, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000193 }
194 RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
195 // Context is returned in both r0 and cp. It replaces the context
196 // passed to us. It's saved in the stack and kept live in cp.
197 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
198 // Copy any necessary parameters into the context.
199 int num_parameters = scope()->num_parameters();
200 for (int i = 0; i < num_parameters; i++) {
201 Slot* slot = scope()->parameter(i)->AsSlot();
202 if (slot != NULL && slot->type() == Slot::CONTEXT) {
203 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
204 (num_parameters - 1 - i) * kPointerSize;
205 // Load parameter from stack.
206 __ ldr(r0, MemOperand(fp, parameter_offset));
207 // Store it in the context.
208 __ mov(r1, Operand(Context::SlotOffset(slot->index())));
209 __ str(r0, MemOperand(cp, r1));
210 // Update the write barrier. This clobbers all involved
211 // registers, so we have to use two more registers to avoid
212 // clobbering cp.
213 __ mov(r2, Operand(cp));
214 __ RecordWrite(r2, Operand(r1), r3, r0);
215 }
216 }
217 Comment(";;; End allocate local context");
218 }
219
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000220 // Trace the call.
221 if (FLAG_trace) {
222 __ CallRuntime(Runtime::kTraceEnter, 0);
223 }
224 return !is_aborted();
225}
226
227
228bool LCodeGen::GenerateBody() {
229 ASSERT(is_generating());
230 bool emit_instructions = true;
231 for (current_instruction_ = 0;
232 !is_aborted() && current_instruction_ < instructions_->length();
233 current_instruction_++) {
234 LInstruction* instr = instructions_->at(current_instruction_);
235 if (instr->IsLabel()) {
236 LLabel* label = LLabel::cast(instr);
237 emit_instructions = !label->HasReplacement();
238 }
239
240 if (emit_instructions) {
241 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic());
242 instr->CompileToNative(this);
243 }
244 }
245 return !is_aborted();
246}
247
248
249LInstruction* LCodeGen::GetNextInstruction() {
250 if (current_instruction_ < instructions_->length() - 1) {
251 return instructions_->at(current_instruction_ + 1);
252 } else {
253 return NULL;
254 }
255}
256
257
258bool LCodeGen::GenerateDeferredCode() {
259 ASSERT(is_generating());
260 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
261 LDeferredCode* code = deferred_[i];
262 __ bind(code->entry());
263 code->Generate();
264 __ jmp(code->exit());
265 }
266
danno@chromium.org40cb8782011-05-25 07:58:50 +0000267 // Force constant pool emission at the end of the deferred code to make
268 // sure that no constant pools are emitted after.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000269 masm()->CheckConstPool(true, false);
270
danno@chromium.org40cb8782011-05-25 07:58:50 +0000271 return !is_aborted();
272}
273
274
275bool LCodeGen::GenerateDeoptJumpTable() {
276 // Check that the jump table is accessible from everywhere in the function
277 // code, ie that offsets to the table can be encoded in the 24bit signed
278 // immediate of a branch instruction.
279 // To simplify we consider the code size from the first instruction to the
280 // end of the jump table. We also don't consider the pc load delta.
281 // Each entry in the jump table generates one instruction and inlines one
282 // 32bit data after it.
283 if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) +
284 deopt_jump_table_.length() * 2)) {
285 Abort("Generated code is too large");
286 }
287
288 // Block the constant pool emission during the jump table emission.
289 __ BlockConstPoolFor(deopt_jump_table_.length());
290 __ RecordComment("[ Deoptimisation jump table");
291 Label table_start;
292 __ bind(&table_start);
293 for (int i = 0; i < deopt_jump_table_.length(); i++) {
294 __ bind(&deopt_jump_table_[i].label);
295 __ ldr(pc, MemOperand(pc, Assembler::kInstrSize - Assembler::kPcLoadDelta));
296 __ dd(reinterpret_cast<uint32_t>(deopt_jump_table_[i].address));
297 }
298 ASSERT(masm()->InstructionsGeneratedSince(&table_start) ==
299 deopt_jump_table_.length() * 2);
300 __ RecordComment("]");
301
302 // The deoptimization jump table is the last part of the instruction
303 // sequence. Mark the generated code as done unless we bailed out.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000304 if (!is_aborted()) status_ = DONE;
305 return !is_aborted();
306}
307
308
309bool LCodeGen::GenerateSafepointTable() {
310 ASSERT(is_done());
danno@chromium.org160a7b02011-04-18 15:51:38 +0000311 safepoints_.Emit(masm(), GetStackSlotCount());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000312 return !is_aborted();
313}
314
315
316Register LCodeGen::ToRegister(int index) const {
317 return Register::FromAllocationIndex(index);
318}
319
320
321DoubleRegister LCodeGen::ToDoubleRegister(int index) const {
322 return DoubleRegister::FromAllocationIndex(index);
323}
324
325
326Register LCodeGen::ToRegister(LOperand* op) const {
327 ASSERT(op->IsRegister());
328 return ToRegister(op->index());
329}
330
331
332Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) {
333 if (op->IsRegister()) {
334 return ToRegister(op->index());
335 } else if (op->IsConstantOperand()) {
336 __ mov(scratch, ToOperand(op));
337 return scratch;
338 } else if (op->IsStackSlot() || op->IsArgument()) {
339 __ ldr(scratch, ToMemOperand(op));
340 return scratch;
341 }
342 UNREACHABLE();
343 return scratch;
344}
345
346
347DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
348 ASSERT(op->IsDoubleRegister());
349 return ToDoubleRegister(op->index());
350}
351
352
353DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op,
354 SwVfpRegister flt_scratch,
355 DoubleRegister dbl_scratch) {
356 if (op->IsDoubleRegister()) {
357 return ToDoubleRegister(op->index());
358 } else if (op->IsConstantOperand()) {
359 LConstantOperand* const_op = LConstantOperand::cast(op);
360 Handle<Object> literal = chunk_->LookupLiteral(const_op);
361 Representation r = chunk_->LookupLiteralRepresentation(const_op);
362 if (r.IsInteger32()) {
363 ASSERT(literal->IsNumber());
364 __ mov(ip, Operand(static_cast<int32_t>(literal->Number())));
365 __ vmov(flt_scratch, ip);
366 __ vcvt_f64_s32(dbl_scratch, flt_scratch);
367 return dbl_scratch;
368 } else if (r.IsDouble()) {
369 Abort("unsupported double immediate");
370 } else if (r.IsTagged()) {
371 Abort("unsupported tagged immediate");
372 }
373 } else if (op->IsStackSlot() || op->IsArgument()) {
374 // TODO(regis): Why is vldr not taking a MemOperand?
375 // __ vldr(dbl_scratch, ToMemOperand(op));
376 MemOperand mem_op = ToMemOperand(op);
377 __ vldr(dbl_scratch, mem_op.rn(), mem_op.offset());
378 return dbl_scratch;
379 }
380 UNREACHABLE();
381 return dbl_scratch;
382}
383
384
385int LCodeGen::ToInteger32(LConstantOperand* op) const {
386 Handle<Object> value = chunk_->LookupLiteral(op);
387 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32());
388 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) ==
389 value->Number());
390 return static_cast<int32_t>(value->Number());
391}
392
393
394Operand LCodeGen::ToOperand(LOperand* op) {
395 if (op->IsConstantOperand()) {
396 LConstantOperand* const_op = LConstantOperand::cast(op);
397 Handle<Object> literal = chunk_->LookupLiteral(const_op);
398 Representation r = chunk_->LookupLiteralRepresentation(const_op);
399 if (r.IsInteger32()) {
400 ASSERT(literal->IsNumber());
401 return Operand(static_cast<int32_t>(literal->Number()));
402 } else if (r.IsDouble()) {
403 Abort("ToOperand Unsupported double immediate.");
404 }
405 ASSERT(r.IsTagged());
406 return Operand(literal);
407 } else if (op->IsRegister()) {
408 return Operand(ToRegister(op));
409 } else if (op->IsDoubleRegister()) {
410 Abort("ToOperand IsDoubleRegister unimplemented");
411 return Operand(0);
412 }
413 // Stack slots not implemented, use ToMemOperand instead.
414 UNREACHABLE();
415 return Operand(0);
416}
417
418
419MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000420 ASSERT(!op->IsRegister());
421 ASSERT(!op->IsDoubleRegister());
422 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
423 int index = op->index();
424 if (index >= 0) {
425 // Local or spill slot. Skip the frame pointer, function, and
426 // context in the fixed part of the frame.
427 return MemOperand(fp, -(index + 3) * kPointerSize);
428 } else {
429 // Incoming parameter. Skip the return address.
430 return MemOperand(fp, -(index - 1) * kPointerSize);
431 }
432}
433
434
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000435MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
436 ASSERT(op->IsDoubleStackSlot());
437 int index = op->index();
438 if (index >= 0) {
439 // Local or spill slot. Skip the frame pointer, function, context,
440 // and the first word of the double in the fixed part of the frame.
441 return MemOperand(fp, -(index + 3) * kPointerSize + kPointerSize);
442 } else {
443 // Incoming parameter. Skip the return address and the first word of
444 // the double.
445 return MemOperand(fp, -(index - 1) * kPointerSize + kPointerSize);
446 }
447}
448
449
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000450void LCodeGen::WriteTranslation(LEnvironment* environment,
451 Translation* translation) {
452 if (environment == NULL) return;
453
454 // The translation includes one command per value in the environment.
455 int translation_size = environment->values()->length();
456 // The output frame height does not include the parameters.
457 int height = translation_size - environment->parameter_count();
458
459 WriteTranslation(environment->outer(), translation);
460 int closure_id = DefineDeoptimizationLiteral(environment->closure());
461 translation->BeginFrame(environment->ast_id(), closure_id, height);
462 for (int i = 0; i < translation_size; ++i) {
463 LOperand* value = environment->values()->at(i);
464 // spilled_registers_ and spilled_double_registers_ are either
465 // both NULL or both set.
466 if (environment->spilled_registers() != NULL && value != NULL) {
467 if (value->IsRegister() &&
468 environment->spilled_registers()[value->index()] != NULL) {
469 translation->MarkDuplicate();
470 AddToTranslation(translation,
471 environment->spilled_registers()[value->index()],
472 environment->HasTaggedValueAt(i));
473 } else if (
474 value->IsDoubleRegister() &&
475 environment->spilled_double_registers()[value->index()] != NULL) {
476 translation->MarkDuplicate();
477 AddToTranslation(
478 translation,
479 environment->spilled_double_registers()[value->index()],
480 false);
481 }
482 }
483
484 AddToTranslation(translation, value, environment->HasTaggedValueAt(i));
485 }
486}
487
488
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000489void LCodeGen::AddToTranslation(Translation* translation,
490 LOperand* op,
491 bool is_tagged) {
492 if (op == NULL) {
493 // TODO(twuerthinger): Introduce marker operands to indicate that this value
494 // is not present and must be reconstructed from the deoptimizer. Currently
495 // this is only used for the arguments object.
496 translation->StoreArgumentsObject();
497 } else if (op->IsStackSlot()) {
498 if (is_tagged) {
499 translation->StoreStackSlot(op->index());
500 } else {
501 translation->StoreInt32StackSlot(op->index());
502 }
503 } else if (op->IsDoubleStackSlot()) {
504 translation->StoreDoubleStackSlot(op->index());
505 } else if (op->IsArgument()) {
506 ASSERT(is_tagged);
danno@chromium.org160a7b02011-04-18 15:51:38 +0000507 int src_index = GetStackSlotCount() + op->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000508 translation->StoreStackSlot(src_index);
509 } else if (op->IsRegister()) {
510 Register reg = ToRegister(op);
511 if (is_tagged) {
512 translation->StoreRegister(reg);
513 } else {
514 translation->StoreInt32Register(reg);
515 }
516 } else if (op->IsDoubleRegister()) {
517 DoubleRegister reg = ToDoubleRegister(op);
518 translation->StoreDoubleRegister(reg);
519 } else if (op->IsConstantOperand()) {
520 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op));
521 int src_index = DefineDeoptimizationLiteral(literal);
522 translation->StoreLiteral(src_index);
523 } else {
524 UNREACHABLE();
525 }
526}
527
528
529void LCodeGen::CallCode(Handle<Code> code,
530 RelocInfo::Mode mode,
531 LInstruction* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000532 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
533}
534
535
536void LCodeGen::CallCodeGeneric(Handle<Code> code,
537 RelocInfo::Mode mode,
538 LInstruction* instr,
539 SafepointMode safepoint_mode) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000540 ASSERT(instr != NULL);
541 LPointerMap* pointers = instr->pointer_map();
542 RecordPosition(pointers->position());
543 __ Call(code, mode);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000544 RegisterLazyDeoptimization(instr, safepoint_mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000545}
546
547
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548void LCodeGen::CallRuntime(const Runtime::Function* function,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 int num_arguments,
550 LInstruction* instr) {
551 ASSERT(instr != NULL);
552 LPointerMap* pointers = instr->pointer_map();
553 ASSERT(pointers != NULL);
554 RecordPosition(pointers->position());
555
556 __ CallRuntime(function, num_arguments);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000557 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000558}
559
560
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000561void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
562 int argc,
563 LInstruction* instr) {
564 __ CallRuntimeSaveDoubles(id);
565 RecordSafepointWithRegisters(
566 instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
567}
568
569
570void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
571 SafepointMode safepoint_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000572 // Create the environment to bailout to. If the call has side effects
573 // execution has to continue after the call otherwise execution can continue
574 // from a previous bailout point repeating the call.
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000575 LEnvironment* deoptimization_environment;
576 if (instr->HasDeoptimizationEnvironment()) {
577 deoptimization_environment = instr->deoptimization_environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000578 } else {
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000579 deoptimization_environment = instr->environment();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000580 }
581
fschneider@chromium.org1df6b472011-01-26 08:23:03 +0000582 RegisterEnvironmentForDeoptimization(deoptimization_environment);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000583 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
584 RecordSafepoint(instr->pointer_map(),
585 deoptimization_environment->deoptimization_index());
586 } else {
587 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
588 RecordSafepointWithRegisters(
589 instr->pointer_map(),
590 0,
591 deoptimization_environment->deoptimization_index());
592 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000593}
594
595
596void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
597 if (!environment->HasBeenRegistered()) {
598 // Physical stack frame layout:
599 // -x ............. -4 0 ..................................... y
600 // [incoming arguments] [spill slots] [pushed outgoing arguments]
601
602 // Layout of the environment:
603 // 0 ..................................................... size-1
604 // [parameters] [locals] [expression stack including arguments]
605
606 // Layout of the translation:
607 // 0 ........................................................ size - 1 + 4
608 // [expression stack including arguments] [locals] [4 words] [parameters]
609 // |>------------ translation_size ------------<|
610
611 int frame_count = 0;
612 for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
613 ++frame_count;
614 }
615 Translation translation(&translations_, frame_count);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000616 WriteTranslation(environment, &translation);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000617 int deoptimization_index = deoptimizations_.length();
618 environment->Register(deoptimization_index, translation.index());
619 deoptimizations_.Add(environment);
620 }
621}
622
623
624void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
625 RegisterEnvironmentForDeoptimization(environment);
626 ASSERT(environment->HasBeenRegistered());
627 int id = environment->deoptimization_index();
628 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
629 ASSERT(entry != NULL);
630 if (entry == NULL) {
631 Abort("bailout was not prepared");
632 return;
633 }
634
635 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on ARM.
636
637 if (FLAG_deopt_every_n_times == 1 &&
638 info_->shared_info()->opt_count() == id) {
639 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
640 return;
641 }
642
danno@chromium.org40cb8782011-05-25 07:58:50 +0000643 if (FLAG_trap_on_deopt) __ stop("trap_on_deopt", cc);
644
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000645 if (cc == al) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
647 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000648 // We often have several deopts to the same entry, reuse the last
649 // jump entry if this is the case.
650 if (deopt_jump_table_.is_empty() ||
651 (deopt_jump_table_.last().address != entry)) {
652 deopt_jump_table_.Add(JumpTableEntry(entry));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000653 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000654 __ b(cc, &deopt_jump_table_.last().label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000655 }
656}
657
658
659void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
660 int length = deoptimizations_.length();
661 if (length == 0) return;
662 ASSERT(FLAG_deopt);
663 Handle<DeoptimizationInputData> data =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000664 factory()->NewDeoptimizationInputData(length, TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000665
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000666 Handle<ByteArray> translations = translations_.CreateByteArray();
667 data->SetTranslationByteArray(*translations);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000668 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
669
670 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000671 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000672 for (int i = 0; i < deoptimization_literals_.length(); i++) {
673 literals->set(i, *deoptimization_literals_[i]);
674 }
675 data->SetLiteralArray(*literals);
676
677 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id()));
678 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
679
680 // Populate the deoptimization entries.
681 for (int i = 0; i < length; i++) {
682 LEnvironment* env = deoptimizations_[i];
683 data->SetAstId(i, Smi::FromInt(env->ast_id()));
684 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
685 data->SetArgumentsStackHeight(i,
686 Smi::FromInt(env->arguments_stack_height()));
687 }
688 code->set_deoptimization_data(*data);
689}
690
691
692int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
693 int result = deoptimization_literals_.length();
694 for (int i = 0; i < deoptimization_literals_.length(); ++i) {
695 if (deoptimization_literals_[i].is_identical_to(literal)) return i;
696 }
697 deoptimization_literals_.Add(literal);
698 return result;
699}
700
701
702void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
703 ASSERT(deoptimization_literals_.length() == 0);
704
705 const ZoneList<Handle<JSFunction> >* inlined_closures =
706 chunk()->inlined_closures();
707
708 for (int i = 0, length = inlined_closures->length();
709 i < length;
710 i++) {
711 DefineDeoptimizationLiteral(inlined_closures->at(i));
712 }
713
714 inlined_function_count_ = deoptimization_literals_.length();
715}
716
717
ager@chromium.org378b34e2011-01-28 08:04:38 +0000718void LCodeGen::RecordSafepoint(
719 LPointerMap* pointers,
720 Safepoint::Kind kind,
721 int arguments,
722 int deoptimization_index) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000723 ASSERT(expected_safepoint_kind_ == kind);
724
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000725 const ZoneList<LOperand*>* operands = pointers->operands();
726 Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
ager@chromium.org378b34e2011-01-28 08:04:38 +0000727 kind, arguments, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000728 for (int i = 0; i < operands->length(); i++) {
729 LOperand* pointer = operands->at(i);
730 if (pointer->IsStackSlot()) {
731 safepoint.DefinePointerSlot(pointer->index());
ager@chromium.org378b34e2011-01-28 08:04:38 +0000732 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
733 safepoint.DefinePointerRegister(ToRegister(pointer));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000734 }
735 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000736 if (kind & Safepoint::kWithRegisters) {
737 // Register cp always contains a pointer to the context.
738 safepoint.DefinePointerRegister(cp);
739 }
740}
741
742
743void LCodeGen::RecordSafepoint(LPointerMap* pointers,
744 int deoptimization_index) {
745 RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000746}
747
748
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000749void LCodeGen::RecordSafepoint(int deoptimization_index) {
750 LPointerMap empty_pointers(RelocInfo::kNoPosition);
751 RecordSafepoint(&empty_pointers, deoptimization_index);
752}
753
754
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000755void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
756 int arguments,
757 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000758 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
759 deoptimization_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000760}
761
762
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000763void LCodeGen::RecordSafepointWithRegistersAndDoubles(
764 LPointerMap* pointers,
765 int arguments,
766 int deoptimization_index) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000767 RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments,
768 deoptimization_index);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000769}
770
771
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000772void LCodeGen::RecordPosition(int position) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000773 if (position == RelocInfo::kNoPosition) return;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000774 masm()->positions_recorder()->RecordPosition(position);
775}
776
777
778void LCodeGen::DoLabel(LLabel* label) {
779 if (label->is_loop_header()) {
780 Comment(";;; B%d - LOOP entry", label->block_id());
781 } else {
782 Comment(";;; B%d", label->block_id());
783 }
784 __ bind(label->label());
785 current_block_ = label->block_id();
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000786 DoGap(label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000787}
788
789
790void LCodeGen::DoParallelMove(LParallelMove* move) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000791 resolver_.Resolve(move);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000792}
793
794
795void LCodeGen::DoGap(LGap* gap) {
796 for (int i = LGap::FIRST_INNER_POSITION;
797 i <= LGap::LAST_INNER_POSITION;
798 i++) {
799 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
800 LParallelMove* move = gap->GetParallelMove(inner_pos);
801 if (move != NULL) DoParallelMove(move);
802 }
803
804 LInstruction* next = GetNextInstruction();
805 if (next != NULL && next->IsLazyBailout()) {
806 int pc = masm()->pc_offset();
807 safepoints_.SetPcAfterGap(pc);
808 }
809}
810
811
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000812void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
813 DoGap(instr);
814}
815
816
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000817void LCodeGen::DoParameter(LParameter* instr) {
818 // Nothing to do.
819}
820
821
822void LCodeGen::DoCallStub(LCallStub* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000823 ASSERT(ToRegister(instr->result()).is(r0));
824 switch (instr->hydrogen()->major_key()) {
825 case CodeStub::RegExpConstructResult: {
826 RegExpConstructResultStub stub;
827 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
828 break;
829 }
830 case CodeStub::RegExpExec: {
831 RegExpExecStub stub;
832 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
833 break;
834 }
835 case CodeStub::SubString: {
836 SubStringStub stub;
837 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
838 break;
839 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000840 case CodeStub::NumberToString: {
841 NumberToStringStub stub;
842 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
843 break;
844 }
845 case CodeStub::StringAdd: {
846 StringAddStub stub(NO_STRING_ADD_FLAGS);
847 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
848 break;
849 }
850 case CodeStub::StringCompare: {
851 StringCompareStub stub;
852 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
853 break;
854 }
855 case CodeStub::TranscendentalCache: {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000856 __ ldr(r0, MemOperand(sp, 0));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000857 TranscendentalCacheStub stub(instr->transcendental_type(),
858 TranscendentalCacheStub::TAGGED);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000859 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000860 break;
861 }
862 default:
863 UNREACHABLE();
864 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000865}
866
867
868void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
869 // Nothing to do.
870}
871
872
873void LCodeGen::DoModI(LModI* instr) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000874 if (instr->hydrogen()->HasPowerOf2Divisor()) {
875 Register dividend = ToRegister(instr->InputAt(0));
876
877 int32_t divisor =
878 HConstant::cast(instr->hydrogen()->right())->Integer32Value();
879
880 if (divisor < 0) divisor = -divisor;
881
882 Label positive_dividend, done;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 __ cmp(dividend, Operand(0));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000884 __ b(pl, &positive_dividend);
885 __ rsb(dividend, dividend, Operand(0));
886 __ and_(dividend, dividend, Operand(divisor - 1));
887 __ rsb(dividend, dividend, Operand(0), SetCC);
888 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
889 __ b(ne, &done);
890 DeoptimizeIf(al, instr->environment());
891 }
892 __ bind(&positive_dividend);
893 __ and_(dividend, dividend, Operand(divisor - 1));
894 __ bind(&done);
895 return;
896 }
897
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000898 // These registers hold untagged 32 bit values.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000899 Register left = ToRegister(instr->InputAt(0));
900 Register right = ToRegister(instr->InputAt(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000901 Register result = ToRegister(instr->result());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000902
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 Register scratch = scratch0();
904 Register scratch2 = ToRegister(instr->TempAt(0));
905 DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1));
906 DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
907 DwVfpRegister quotient = double_scratch0();
908
909 ASSERT(result.is(left));
910
911 ASSERT(!dividend.is(divisor));
912 ASSERT(!dividend.is(quotient));
913 ASSERT(!divisor.is(quotient));
914 ASSERT(!scratch.is(left));
915 ASSERT(!scratch.is(right));
916 ASSERT(!scratch.is(result));
917
918 Label done, vfp_modulo, both_positive, right_negative;
919
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000920 // Check for x % 0.
921 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 __ cmp(right, Operand(0));
923 DeoptimizeIf(eq, instr->environment());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000924 }
925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 // (0 % x) must yield 0 (if x is finite, which is the case here).
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000927 __ cmp(left, Operand(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 __ b(eq, &done);
929 // Preload right in a vfp register.
930 __ vmov(divisor.low(), right);
931 __ b(lt, &vfp_modulo);
932
933 __ cmp(left, Operand(right));
934 __ b(lt, &done);
935
936 // Check for (positive) power of two on the right hand side.
937 __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
938 scratch,
939 &right_negative,
940 &both_positive);
941 // Perform modulo operation (scratch contains right - 1).
942 __ and_(result, scratch, Operand(left));
943 __ b(&done);
944
945 __ bind(&right_negative);
946 // Negate right. The sign of the divisor does not matter.
947 __ rsb(right, right, Operand(0));
948
949 __ bind(&both_positive);
950 const int kUnfolds = 3;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000951 // If the right hand side is smaller than the (nonnegative)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 // left hand side, the left hand side is the result.
953 // Else try a few subtractions of the left hand side.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000954 __ mov(scratch, left);
955 for (int i = 0; i < kUnfolds; i++) {
956 // Check if the left hand side is less or equal than the
957 // the right hand side.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 __ cmp(scratch, Operand(right));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000959 __ mov(result, scratch, LeaveCC, lt);
960 __ b(lt, &done);
961 // If not, reduce the left hand side by the right hand
962 // side and check again.
963 if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
964 }
965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000966 __ bind(&vfp_modulo);
967 // Load the arguments in VFP registers.
968 // The divisor value is preloaded before. Be careful that 'right' is only live
969 // on entry.
970 __ vmov(dividend.low(), left);
971 // From here on don't use right as it may have been reallocated (for example
972 // to scratch2).
973 right = no_reg;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 __ vcvt_f64_s32(dividend, dividend.low());
976 __ vcvt_f64_s32(divisor, divisor.low());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 // We do not care about the sign of the divisor.
979 __ vabs(divisor, divisor);
980 // Compute the quotient and round it to a 32bit integer.
981 __ vdiv(quotient, dividend, divisor);
982 __ vcvt_s32_f64(quotient.low(), quotient);
983 __ vcvt_f64_s32(quotient, quotient.low());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000985 // Compute the remainder in result.
986 DwVfpRegister double_scratch = dividend;
987 __ vmul(double_scratch, divisor, quotient);
988 __ vcvt_s32_f64(double_scratch.low(), double_scratch);
989 __ vmov(scratch, double_scratch.low());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
992 __ sub(result, left, scratch);
993 } else {
994 Label ok;
995 // Check for -0.
996 __ sub(scratch2, left, scratch, SetCC);
997 __ b(ne, &ok);
998 __ cmp(left, Operand(0));
999 DeoptimizeIf(mi, instr->environment());
1000 __ bind(&ok);
1001 // Load the result and we are done.
1002 __ mov(result, scratch2);
1003 }
1004
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001005 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006}
1007
1008
1009void LCodeGen::DoDivI(LDivI* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001010 class DeferredDivI: public LDeferredCode {
1011 public:
1012 DeferredDivI(LCodeGen* codegen, LDivI* instr)
1013 : LDeferredCode(codegen), instr_(instr) { }
1014 virtual void Generate() {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001015 codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001016 }
1017 private:
1018 LDivI* instr_;
1019 };
1020
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001021 const Register left = ToRegister(instr->InputAt(0));
1022 const Register right = ToRegister(instr->InputAt(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001023 const Register scratch = scratch0();
1024 const Register result = ToRegister(instr->result());
1025
1026 // Check for x / 0.
1027 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 __ cmp(right, Operand(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001029 DeoptimizeIf(eq, instr->environment());
1030 }
1031
1032 // Check for (0 / -x) that will produce negative zero.
1033 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1034 Label left_not_zero;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 __ cmp(left, Operand(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001036 __ b(ne, &left_not_zero);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 __ cmp(right, Operand(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001038 DeoptimizeIf(mi, instr->environment());
1039 __ bind(&left_not_zero);
1040 }
1041
1042 // Check for (-kMinInt / -1).
1043 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1044 Label left_not_min_int;
1045 __ cmp(left, Operand(kMinInt));
1046 __ b(ne, &left_not_min_int);
1047 __ cmp(right, Operand(-1));
1048 DeoptimizeIf(eq, instr->environment());
1049 __ bind(&left_not_min_int);
1050 }
1051
1052 Label done, deoptimize;
1053 // Test for a few common cases first.
1054 __ cmp(right, Operand(1));
1055 __ mov(result, left, LeaveCC, eq);
1056 __ b(eq, &done);
1057
1058 __ cmp(right, Operand(2));
1059 __ tst(left, Operand(1), eq);
1060 __ mov(result, Operand(left, ASR, 1), LeaveCC, eq);
1061 __ b(eq, &done);
1062
1063 __ cmp(right, Operand(4));
1064 __ tst(left, Operand(3), eq);
1065 __ mov(result, Operand(left, ASR, 2), LeaveCC, eq);
1066 __ b(eq, &done);
1067
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001068 // Call the stub. The numbers in r0 and r1 have
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001069 // to be tagged to Smis. If that is not possible, deoptimize.
1070 DeferredDivI* deferred = new DeferredDivI(this, instr);
1071
1072 __ TrySmiTag(left, &deoptimize, scratch);
1073 __ TrySmiTag(right, &deoptimize, scratch);
1074
1075 __ b(al, deferred->entry());
1076 __ bind(deferred->exit());
1077
1078 // If the result in r0 is a Smi, untag it, else deoptimize.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001079 __ JumpIfNotSmi(result, &deoptimize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001080 __ SmiUntag(result);
1081 __ b(&done);
1082
1083 __ bind(&deoptimize);
1084 DeoptimizeIf(al, instr->environment());
1085 __ bind(&done);
1086}
1087
1088
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001089template<int T>
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001090void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
1091 Token::Value op) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001092 Register left = ToRegister(instr->InputAt(0));
1093 Register right = ToRegister(instr->InputAt(1));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001094
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001095 PushSafepointRegistersScope scope(this, Safepoint::kWithRegistersAndDoubles);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001096 // Move left to r1 and right to r0 for the stub call.
1097 if (left.is(r1)) {
1098 __ Move(r0, right);
1099 } else if (left.is(r0) && right.is(r1)) {
1100 __ Swap(r0, r1, r2);
1101 } else if (left.is(r0)) {
1102 ASSERT(!right.is(r1));
1103 __ mov(r1, r0);
1104 __ mov(r0, right);
1105 } else {
1106 ASSERT(!left.is(r0) && !right.is(r0));
1107 __ mov(r0, right);
1108 __ mov(r1, left);
1109 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00001110 BinaryOpStub stub(op, OVERWRITE_LEFT);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001111 __ CallStub(&stub);
1112 RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
1113 0,
1114 Safepoint::kNoDeoptimizationIndex);
1115 // Overwrite the stored value of r0 with the result of the stub.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001116 __ StoreToSafepointRegistersAndDoublesSlot(r0, r0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001117}
1118
1119
1120void LCodeGen::DoMulI(LMulI* instr) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001121 ASSERT(instr->result()->Equals(instr->InputAt(0)));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001122 Register scratch = scratch0();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001123 Register result = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001124 Register left = ToRegister(instr->InputAt(0));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001125 LOperand* right_op = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001126
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001127 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1128 bool bailout_on_minus_zero =
1129 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001130
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001131 if (right_op->IsConstantOperand() && !can_overflow) {
1132 // Use optimized code for specific constants.
1133 int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
1134
1135 if (bailout_on_minus_zero && (constant < 0)) {
1136 // The case of a null constant will be handled separately.
1137 // If constant is negative and left is null, the result should be -0.
1138 __ cmp(left, Operand(0));
1139 DeoptimizeIf(eq, instr->environment());
1140 }
1141
1142 switch (constant) {
1143 case -1:
1144 __ rsb(result, left, Operand(0));
1145 break;
1146 case 0:
1147 if (bailout_on_minus_zero) {
1148 // If left is strictly negative and the constant is null, the
1149 // result is -0. Deoptimize if required, otherwise return 0.
1150 __ cmp(left, Operand(0));
1151 DeoptimizeIf(mi, instr->environment());
1152 }
1153 __ mov(result, Operand(0));
1154 break;
1155 case 1:
1156 // Nothing to do.
1157 break;
1158 default:
1159 // Multiplying by powers of two and powers of two plus or minus
1160 // one can be done faster with shifted operands.
1161 // For other constants we emit standard code.
1162 int32_t mask = constant >> 31;
1163 uint32_t constant_abs = (constant + mask) ^ mask;
1164
1165 if (IsPowerOf2(constant_abs) ||
1166 IsPowerOf2(constant_abs - 1) ||
1167 IsPowerOf2(constant_abs + 1)) {
1168 if (IsPowerOf2(constant_abs)) {
1169 int32_t shift = WhichPowerOf2(constant_abs);
1170 __ mov(result, Operand(left, LSL, shift));
1171 } else if (IsPowerOf2(constant_abs - 1)) {
1172 int32_t shift = WhichPowerOf2(constant_abs - 1);
1173 __ add(result, left, Operand(left, LSL, shift));
1174 } else if (IsPowerOf2(constant_abs + 1)) {
1175 int32_t shift = WhichPowerOf2(constant_abs + 1);
1176 __ rsb(result, left, Operand(left, LSL, shift));
1177 }
1178
1179 // Correct the sign of the result is the constant is negative.
1180 if (constant < 0) __ rsb(result, result, Operand(0));
1181
1182 } else {
1183 // Generate standard code.
1184 __ mov(ip, Operand(constant));
1185 __ mul(result, left, ip);
1186 }
1187 }
1188
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001189 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001190 Register right = EmitLoadRegister(right_op, scratch);
1191 if (bailout_on_minus_zero) {
1192 __ orr(ToRegister(instr->TempAt(0)), left, right);
1193 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001194
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001195 if (can_overflow) {
1196 // scratch:result = left * right.
1197 __ smull(result, scratch, left, right);
1198 __ cmp(scratch, Operand(result, ASR, 31));
1199 DeoptimizeIf(ne, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001200 } else {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001201 __ mul(result, left, right);
1202 }
1203
1204 if (bailout_on_minus_zero) {
1205 // Bail out if the result is supposed to be negative zero.
1206 Label done;
1207 __ cmp(result, Operand(0));
1208 __ b(ne, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001209 __ cmp(ToRegister(instr->TempAt(0)), Operand(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001210 DeoptimizeIf(mi, instr->environment());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001211 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001212 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001213 }
1214}
1215
1216
1217void LCodeGen::DoBitI(LBitI* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001218 LOperand* left = instr->InputAt(0);
1219 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001220 ASSERT(left->Equals(instr->result()));
1221 ASSERT(left->IsRegister());
1222 Register result = ToRegister(left);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001223 Operand right_operand(no_reg);
1224
1225 if (right->IsStackSlot() || right->IsArgument()) {
1226 Register right_reg = EmitLoadRegister(right, ip);
1227 right_operand = Operand(right_reg);
1228 } else {
1229 ASSERT(right->IsRegister() || right->IsConstantOperand());
1230 right_operand = ToOperand(right);
1231 }
1232
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001233 switch (instr->op()) {
1234 case Token::BIT_AND:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001235 __ and_(result, ToRegister(left), right_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001236 break;
1237 case Token::BIT_OR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001238 __ orr(result, ToRegister(left), right_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001239 break;
1240 case Token::BIT_XOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001241 __ eor(result, ToRegister(left), right_operand);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001242 break;
1243 default:
1244 UNREACHABLE();
1245 break;
1246 }
1247}
1248
1249
1250void LCodeGen::DoShiftI(LShiftI* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001251 Register scratch = scratch0();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001252 LOperand* left = instr->InputAt(0);
1253 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001254 ASSERT(left->Equals(instr->result()));
1255 ASSERT(left->IsRegister());
1256 Register result = ToRegister(left);
1257 if (right->IsRegister()) {
1258 // Mask the right operand.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001259 __ and_(scratch, ToRegister(right), Operand(0x1F));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001260 switch (instr->op()) {
1261 case Token::SAR:
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001262 __ mov(result, Operand(result, ASR, scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001263 break;
1264 case Token::SHR:
1265 if (instr->can_deopt()) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001266 __ mov(result, Operand(result, LSR, scratch), SetCC);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001267 DeoptimizeIf(mi, instr->environment());
1268 } else {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001269 __ mov(result, Operand(result, LSR, scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001270 }
1271 break;
1272 case Token::SHL:
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001273 __ mov(result, Operand(result, LSL, scratch));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274 break;
1275 default:
1276 UNREACHABLE();
1277 break;
1278 }
1279 } else {
1280 int value = ToInteger32(LConstantOperand::cast(right));
1281 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1282 switch (instr->op()) {
1283 case Token::SAR:
1284 if (shift_count != 0) {
1285 __ mov(result, Operand(result, ASR, shift_count));
1286 }
1287 break;
1288 case Token::SHR:
1289 if (shift_count == 0 && instr->can_deopt()) {
1290 __ tst(result, Operand(0x80000000));
1291 DeoptimizeIf(ne, instr->environment());
1292 } else {
1293 __ mov(result, Operand(result, LSR, shift_count));
1294 }
1295 break;
1296 case Token::SHL:
1297 if (shift_count != 0) {
1298 __ mov(result, Operand(result, LSL, shift_count));
1299 }
1300 break;
1301 default:
1302 UNREACHABLE();
1303 break;
1304 }
1305 }
1306}
1307
1308
1309void LCodeGen::DoSubI(LSubI* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001310 LOperand* left = instr->InputAt(0);
1311 LOperand* right = instr->InputAt(1);
1312 ASSERT(left->Equals(instr->result()));
1313 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1314 SBit set_cond = can_overflow ? SetCC : LeaveCC;
1315
1316 if (right->IsStackSlot() || right->IsArgument()) {
1317 Register right_reg = EmitLoadRegister(right, ip);
1318 __ sub(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
1319 } else {
1320 ASSERT(right->IsRegister() || right->IsConstantOperand());
1321 __ sub(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
1322 }
1323
1324 if (can_overflow) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001325 DeoptimizeIf(vs, instr->environment());
1326 }
1327}
1328
1329
1330void LCodeGen::DoConstantI(LConstantI* instr) {
1331 ASSERT(instr->result()->IsRegister());
1332 __ mov(ToRegister(instr->result()), Operand(instr->value()));
1333}
1334
1335
1336void LCodeGen::DoConstantD(LConstantD* instr) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001337 ASSERT(instr->result()->IsDoubleRegister());
1338 DwVfpRegister result = ToDoubleRegister(instr->result());
1339 double v = instr->value();
1340 __ vmov(result, v);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001341}
1342
1343
1344void LCodeGen::DoConstantT(LConstantT* instr) {
1345 ASSERT(instr->result()->IsRegister());
1346 __ mov(ToRegister(instr->result()), Operand(instr->value()));
1347}
1348
1349
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001350void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001351 Register result = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001352 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001353 __ ldr(result, FieldMemOperand(array, JSArray::kLengthOffset));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001354}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001355
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001356
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001357void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001358 Register result = ToRegister(instr->result());
1359 Register array = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001360 __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001361}
1362
1363
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001364void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
1365 Register result = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001366 Register array = ToRegister(instr->InputAt(0));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001367 __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001368}
1369
1370
1371void LCodeGen::DoValueOf(LValueOf* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001372 Register input = ToRegister(instr->InputAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001373 Register result = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001374 Register map = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001375 ASSERT(input.is(result));
1376 Label done;
1377
1378 // If the object is a smi return the object.
1379 __ tst(input, Operand(kSmiTagMask));
1380 __ b(eq, &done);
1381
1382 // If the object is not a value type, return the object.
1383 __ CompareObjectType(input, map, map, JS_VALUE_TYPE);
1384 __ b(ne, &done);
1385 __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset));
1386
1387 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001388}
1389
1390
1391void LCodeGen::DoBitNotI(LBitNotI* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001392 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001393 ASSERT(input->Equals(instr->result()));
1394 __ mvn(ToRegister(input), Operand(ToRegister(input)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001395}
1396
1397
1398void LCodeGen::DoThrow(LThrow* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001399 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001400 __ push(input_reg);
1401 CallRuntime(Runtime::kThrow, 1, instr);
1402
1403 if (FLAG_debug_code) {
1404 __ stop("Unreachable code.");
1405 }
1406}
1407
1408
1409void LCodeGen::DoAddI(LAddI* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001410 LOperand* left = instr->InputAt(0);
1411 LOperand* right = instr->InputAt(1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001412 ASSERT(left->Equals(instr->result()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001413 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
1414 SBit set_cond = can_overflow ? SetCC : LeaveCC;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001415
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001416 if (right->IsStackSlot() || right->IsArgument()) {
1417 Register right_reg = EmitLoadRegister(right, ip);
1418 __ add(ToRegister(left), ToRegister(left), Operand(right_reg), set_cond);
1419 } else {
1420 ASSERT(right->IsRegister() || right->IsConstantOperand());
1421 __ add(ToRegister(left), ToRegister(left), ToOperand(right), set_cond);
1422 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001423
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001424 if (can_overflow) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001425 DeoptimizeIf(vs, instr->environment());
1426 }
1427}
1428
1429
1430void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001431 DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
1432 DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001433 switch (instr->op()) {
1434 case Token::ADD:
1435 __ vadd(left, left, right);
1436 break;
1437 case Token::SUB:
1438 __ vsub(left, left, right);
1439 break;
1440 case Token::MUL:
1441 __ vmul(left, left, right);
1442 break;
1443 case Token::DIV:
1444 __ vdiv(left, left, right);
1445 break;
1446 case Token::MOD: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001447 // Save r0-r3 on the stack.
1448 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
1449
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001450 __ PrepareCallCFunction(0, 2, scratch0());
1451 __ SetCallCDoubleArguments(left, right);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 __ CallCFunction(
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001453 ExternalReference::double_fp_operation(Token::MOD, isolate()),
1454 0, 2);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001455 // Move the result in the double result register.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001457
1458 // Restore r0-r3.
1459 __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001460 break;
1461 }
1462 default:
1463 UNREACHABLE();
1464 break;
1465 }
1466}
1467
1468
1469void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001470 ASSERT(ToRegister(instr->InputAt(0)).is(r1));
1471 ASSERT(ToRegister(instr->InputAt(1)).is(r0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001472 ASSERT(ToRegister(instr->result()).is(r0));
1473
danno@chromium.org40cb8782011-05-25 07:58:50 +00001474 BinaryOpStub stub(instr->op(), NO_OVERWRITE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001475 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1476}
1477
1478
1479int LCodeGen::GetNextEmittedBlock(int block) {
1480 for (int i = block + 1; i < graph()->blocks()->length(); ++i) {
1481 LLabel* label = chunk_->GetLabel(i);
1482 if (!label->HasReplacement()) return i;
1483 }
1484 return -1;
1485}
1486
1487
1488void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
1489 int next_block = GetNextEmittedBlock(current_block_);
1490 right_block = chunk_->LookupDestination(right_block);
1491 left_block = chunk_->LookupDestination(left_block);
1492
1493 if (right_block == left_block) {
1494 EmitGoto(left_block);
1495 } else if (left_block == next_block) {
1496 __ b(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
1497 } else if (right_block == next_block) {
1498 __ b(cc, chunk_->GetAssemblyLabel(left_block));
1499 } else {
1500 __ b(cc, chunk_->GetAssemblyLabel(left_block));
1501 __ b(chunk_->GetAssemblyLabel(right_block));
1502 }
1503}
1504
1505
1506void LCodeGen::DoBranch(LBranch* instr) {
1507 int true_block = chunk_->LookupDestination(instr->true_block_id());
1508 int false_block = chunk_->LookupDestination(instr->false_block_id());
1509
1510 Representation r = instr->hydrogen()->representation();
1511 if (r.IsInteger32()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001512 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001513 __ cmp(reg, Operand(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00001514 EmitBranch(true_block, false_block, ne);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001515 } else if (r.IsDouble()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001516 DoubleRegister reg = ToDoubleRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001517 Register scratch = scratch0();
1518
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001519 // Test the double value. Zero and NaN are false.
1520 __ VFPCompareAndLoadFlags(reg, 0.0, scratch);
1521 __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001522 EmitBranch(true_block, false_block, ne);
1523 } else {
1524 ASSERT(r.IsTagged());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001525 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001526 if (instr->hydrogen()->type().IsBoolean()) {
1527 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1528 __ cmp(reg, ip);
1529 EmitBranch(true_block, false_block, eq);
1530 } else {
1531 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1532 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1533
1534 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1535 __ cmp(reg, ip);
1536 __ b(eq, false_label);
1537 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1538 __ cmp(reg, ip);
1539 __ b(eq, true_label);
1540 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1541 __ cmp(reg, ip);
1542 __ b(eq, false_label);
1543 __ cmp(reg, Operand(0));
1544 __ b(eq, false_label);
1545 __ tst(reg, Operand(kSmiTagMask));
1546 __ b(eq, true_label);
1547
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001548 // Test double values. Zero and NaN are false.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001549 Label call_stub;
1550 DoubleRegister dbl_scratch = d0;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001551 Register scratch = scratch0();
1552 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001553 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001554 __ cmp(scratch, Operand(ip));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001555 __ b(ne, &call_stub);
1556 __ sub(ip, reg, Operand(kHeapObjectTag));
1557 __ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001558 __ VFPCompareAndLoadFlags(dbl_scratch, 0.0, scratch);
1559 __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001560 __ b(ne, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001561 __ b(true_label);
1562
1563 // The conversion stub doesn't cause garbage collections so it's
1564 // safe to not record a safepoint after the call.
1565 __ bind(&call_stub);
1566 ToBooleanStub stub(reg);
1567 RegList saved_regs = kJSCallerSaved | kCalleeSaved;
1568 __ stm(db_w, sp, saved_regs);
1569 __ CallStub(&stub);
1570 __ cmp(reg, Operand(0));
1571 __ ldm(ia_w, sp, saved_regs);
ager@chromium.org378b34e2011-01-28 08:04:38 +00001572 EmitBranch(true_block, false_block, ne);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001573 }
1574 }
1575}
1576
1577
1578void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001579 block = chunk_->LookupDestination(block);
1580 int next_block = GetNextEmittedBlock(current_block_);
1581 if (block != next_block) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001582 // Perform stack overflow check if this goto needs it before jumping.
1583 if (deferred_stack_check != NULL) {
1584 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
1585 __ cmp(sp, Operand(ip));
1586 __ b(hs, chunk_->GetAssemblyLabel(block));
1587 __ jmp(deferred_stack_check->entry());
1588 deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1589 } else {
1590 __ jmp(chunk_->GetAssemblyLabel(block));
1591 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001592 }
1593}
1594
1595
1596void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001597 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
1598 CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001599}
1600
1601
1602void LCodeGen::DoGoto(LGoto* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001603 class DeferredStackCheck: public LDeferredCode {
1604 public:
1605 DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1606 : LDeferredCode(codegen), instr_(instr) { }
1607 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1608 private:
1609 LGoto* instr_;
1610 };
1611
1612 DeferredStackCheck* deferred = NULL;
1613 if (instr->include_stack_check()) {
1614 deferred = new DeferredStackCheck(this, instr);
1615 }
1616 EmitGoto(instr->block_id(), deferred);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617}
1618
1619
1620Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001621 Condition cond = kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001622 switch (op) {
1623 case Token::EQ:
1624 case Token::EQ_STRICT:
1625 cond = eq;
1626 break;
1627 case Token::LT:
1628 cond = is_unsigned ? lo : lt;
1629 break;
1630 case Token::GT:
1631 cond = is_unsigned ? hi : gt;
1632 break;
1633 case Token::LTE:
1634 cond = is_unsigned ? ls : le;
1635 break;
1636 case Token::GTE:
1637 cond = is_unsigned ? hs : ge;
1638 break;
1639 case Token::IN:
1640 case Token::INSTANCEOF:
1641 default:
1642 UNREACHABLE();
1643 }
1644 return cond;
1645}
1646
1647
1648void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001649 __ cmp(ToRegister(left), ToRegister(right));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001650}
1651
1652
1653void LCodeGen::DoCmpID(LCmpID* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001654 LOperand* left = instr->InputAt(0);
1655 LOperand* right = instr->InputAt(1);
1656 LOperand* result = instr->result();
1657 Register scratch = scratch0();
1658
1659 Label unordered, done;
1660 if (instr->is_double()) {
1661 // Compare left and right as doubles and load the
1662 // resulting flags into the normal status register.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001663 __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001664 // If a NaN is involved, i.e. the result is unordered (V set),
1665 // jump to unordered to return false.
1666 __ b(vs, &unordered);
1667 } else {
1668 EmitCmpI(left, right);
1669 }
1670
1671 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1672 __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
1673 __ b(cc, &done);
1674
1675 __ bind(&unordered);
1676 __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
1677 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678}
1679
1680
1681void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001682 LOperand* left = instr->InputAt(0);
1683 LOperand* right = instr->InputAt(1);
1684 int false_block = chunk_->LookupDestination(instr->false_block_id());
1685 int true_block = chunk_->LookupDestination(instr->true_block_id());
1686
1687 if (instr->is_double()) {
1688 // Compare left and right as doubles and load the
1689 // resulting flags into the normal status register.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001690 __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001691 // If a NaN is involved, i.e. the result is unordered (V set),
1692 // jump to false block label.
1693 __ b(vs, chunk_->GetAssemblyLabel(false_block));
1694 } else {
1695 EmitCmpI(left, right);
1696 }
1697
1698 Condition cc = TokenToCondition(instr->op(), instr->is_double());
1699 EmitBranch(true_block, false_block, cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001700}
1701
1702
1703void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001704 Register left = ToRegister(instr->InputAt(0));
1705 Register right = ToRegister(instr->InputAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001706 Register result = ToRegister(instr->result());
1707
1708 __ cmp(left, Operand(right));
1709 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1710 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001711}
1712
1713
1714void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001715 Register left = ToRegister(instr->InputAt(0));
1716 Register right = ToRegister(instr->InputAt(1));
1717 int false_block = chunk_->LookupDestination(instr->false_block_id());
1718 int true_block = chunk_->LookupDestination(instr->true_block_id());
1719
1720 __ cmp(left, Operand(right));
1721 EmitBranch(true_block, false_block, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001722}
1723
1724
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001725void LCodeGen::DoCmpSymbolEq(LCmpSymbolEq* instr) {
1726 Register left = ToRegister(instr->InputAt(0));
1727 Register right = ToRegister(instr->InputAt(1));
1728 Register result = ToRegister(instr->result());
1729
1730 __ cmp(left, Operand(right));
1731 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1732 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
1733}
1734
1735
1736void LCodeGen::DoCmpSymbolEqAndBranch(LCmpSymbolEqAndBranch* instr) {
1737 Register left = ToRegister(instr->InputAt(0));
1738 Register right = ToRegister(instr->InputAt(1));
1739 int false_block = chunk_->LookupDestination(instr->false_block_id());
1740 int true_block = chunk_->LookupDestination(instr->true_block_id());
1741
1742 __ cmp(left, Operand(right));
1743 EmitBranch(true_block, false_block, eq);
1744}
1745
1746
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001747void LCodeGen::DoIsNull(LIsNull* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001748 Register reg = ToRegister(instr->InputAt(0));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001749 Register result = ToRegister(instr->result());
1750
1751 __ LoadRoot(ip, Heap::kNullValueRootIndex);
1752 __ cmp(reg, ip);
1753 if (instr->is_strict()) {
1754 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1755 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
1756 } else {
1757 Label true_value, false_value, done;
1758 __ b(eq, &true_value);
1759 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1760 __ cmp(ip, reg);
1761 __ b(eq, &true_value);
1762 __ tst(reg, Operand(kSmiTagMask));
1763 __ b(eq, &false_value);
1764 // Check for undetectable objects by looking in the bit field in
1765 // the map. The object has already been smi checked.
1766 Register scratch = result;
1767 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
1768 __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
1769 __ tst(scratch, Operand(1 << Map::kIsUndetectable));
1770 __ b(ne, &true_value);
1771 __ bind(&false_value);
1772 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1773 __ jmp(&done);
1774 __ bind(&true_value);
1775 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1776 __ bind(&done);
1777 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001778}
1779
1780
1781void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001782 Register scratch = scratch0();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001783 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001784
1785 // TODO(fsc): If the expression is known to be a smi, then it's
1786 // definitely not null. Jump to the false block.
1787
1788 int true_block = chunk_->LookupDestination(instr->true_block_id());
1789 int false_block = chunk_->LookupDestination(instr->false_block_id());
1790
1791 __ LoadRoot(ip, Heap::kNullValueRootIndex);
1792 __ cmp(reg, ip);
1793 if (instr->is_strict()) {
1794 EmitBranch(true_block, false_block, eq);
1795 } else {
1796 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1797 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1798 __ b(eq, true_label);
1799 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1800 __ cmp(reg, ip);
1801 __ b(eq, true_label);
1802 __ tst(reg, Operand(kSmiTagMask));
1803 __ b(eq, false_label);
1804 // Check for undetectable objects by looking in the bit field in
1805 // the map. The object has already been smi checked.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001806 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
1807 __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
1808 __ tst(scratch, Operand(1 << Map::kIsUndetectable));
1809 EmitBranch(true_block, false_block, ne);
1810 }
1811}
1812
1813
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001814Condition LCodeGen::EmitIsObject(Register input,
1815 Register temp1,
1816 Register temp2,
1817 Label* is_not_object,
1818 Label* is_object) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001819 __ JumpIfSmi(input, is_not_object);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001820
1821 __ LoadRoot(temp1, Heap::kNullValueRootIndex);
1822 __ cmp(input, temp1);
1823 __ b(eq, is_object);
1824
1825 // Load map.
1826 __ ldr(temp1, FieldMemOperand(input, HeapObject::kMapOffset));
1827 // Undetectable objects behave like undefined.
1828 __ ldrb(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset));
1829 __ tst(temp2, Operand(1 << Map::kIsUndetectable));
1830 __ b(ne, is_not_object);
1831
1832 // Load instance type and check that it is in object type range.
1833 __ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001834 __ cmp(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001835 __ b(lt, is_not_object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001836 __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001837 return le;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001838}
1839
1840
1841void LCodeGen::DoIsObject(LIsObject* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001842 Register reg = ToRegister(instr->InputAt(0));
1843 Register result = ToRegister(instr->result());
1844 Register temp = scratch0();
1845 Label is_false, is_true, done;
1846
1847 Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1848 __ b(true_cond, &is_true);
1849
1850 __ bind(&is_false);
1851 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1852 __ b(&done);
1853
1854 __ bind(&is_true);
1855 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1856
1857 __ bind(&done);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001858}
1859
1860
1861void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +00001862 Register reg = ToRegister(instr->InputAt(0));
1863 Register temp1 = ToRegister(instr->TempAt(0));
1864 Register temp2 = scratch0();
1865
1866 int true_block = chunk_->LookupDestination(instr->true_block_id());
1867 int false_block = chunk_->LookupDestination(instr->false_block_id());
1868 Label* true_label = chunk_->GetAssemblyLabel(true_block);
1869 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1870
1871 Condition true_cond =
1872 EmitIsObject(reg, temp1, temp2, false_label, true_label);
1873
1874 EmitBranch(true_block, false_block, true_cond);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001875}
1876
1877
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001878void LCodeGen::DoIsSmi(LIsSmi* instr) {
1879 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1880 Register result = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001881 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001882 __ tst(input_reg, Operand(kSmiTagMask));
1883 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1884 Label done;
1885 __ b(eq, &done);
1886 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1887 __ bind(&done);
1888}
1889
1890
1891void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
1892 int true_block = chunk_->LookupDestination(instr->true_block_id());
1893 int false_block = chunk_->LookupDestination(instr->false_block_id());
1894
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001895 Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 __ tst(input_reg, Operand(kSmiTagMask));
1897 EmitBranch(true_block, false_block, eq);
1898}
1899
1900
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001901void LCodeGen::DoIsUndetectable(LIsUndetectable* instr) {
1902 Register input = ToRegister(instr->InputAt(0));
1903 Register result = ToRegister(instr->result());
1904
1905 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1906 Label false_label, done;
1907 __ JumpIfSmi(input, &false_label);
1908 __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
1909 __ ldrb(result, FieldMemOperand(result, Map::kBitFieldOffset));
1910 __ tst(result, Operand(1 << Map::kIsUndetectable));
1911 __ b(eq, &false_label);
1912 __ LoadRoot(result, Heap::kTrueValueRootIndex);
1913 __ jmp(&done);
1914 __ bind(&false_label);
1915 __ LoadRoot(result, Heap::kFalseValueRootIndex);
1916 __ bind(&done);
1917}
1918
1919
1920void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
1921 Register input = ToRegister(instr->InputAt(0));
1922 Register temp = ToRegister(instr->TempAt(0));
1923
1924 int true_block = chunk_->LookupDestination(instr->true_block_id());
1925 int false_block = chunk_->LookupDestination(instr->false_block_id());
1926
1927 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
1928 __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
1929 __ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
1930 __ tst(temp, Operand(1 << Map::kIsUndetectable));
1931 EmitBranch(true_block, false_block, ne);
1932}
1933
1934
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001935static InstanceType TestType(HHasInstanceType* instr) {
1936 InstanceType from = instr->from();
1937 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001938 if (from == FIRST_TYPE) return to;
1939 ASSERT(from == to || to == LAST_TYPE);
1940 return from;
1941}
1942
1943
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001944static Condition BranchCondition(HHasInstanceType* instr) {
1945 InstanceType from = instr->from();
1946 InstanceType to = instr->to();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001947 if (from == to) return eq;
1948 if (to == LAST_TYPE) return hs;
1949 if (from == FIRST_TYPE) return ls;
1950 UNREACHABLE();
1951 return eq;
1952}
1953
1954
1955void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001956 Register input = ToRegister(instr->InputAt(0));
1957 Register result = ToRegister(instr->result());
1958
1959 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1960 Label done;
1961 __ tst(input, Operand(kSmiTagMask));
1962 __ LoadRoot(result, Heap::kFalseValueRootIndex, eq);
1963 __ b(eq, &done);
1964 __ CompareObjectType(input, result, result, TestType(instr->hydrogen()));
1965 Condition cond = BranchCondition(instr->hydrogen());
1966 __ LoadRoot(result, Heap::kTrueValueRootIndex, cond);
1967 __ LoadRoot(result, Heap::kFalseValueRootIndex, NegateCondition(cond));
1968 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001969}
1970
1971
1972void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001973 Register scratch = scratch0();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001974 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001975
1976 int true_block = chunk_->LookupDestination(instr->true_block_id());
1977 int false_block = chunk_->LookupDestination(instr->false_block_id());
1978
1979 Label* false_label = chunk_->GetAssemblyLabel(false_block);
1980
1981 __ tst(input, Operand(kSmiTagMask));
1982 __ b(eq, false_label);
1983
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001984 __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
1985 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001986}
1987
1988
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001989void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1990 Register input = ToRegister(instr->InputAt(0));
1991 Register result = ToRegister(instr->result());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001992
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001993 if (FLAG_debug_code) {
1994 __ AbortIfNotString(input);
1995 }
1996
1997 __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset));
1998 __ IndexFromHash(result, result);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001999}
2000
2001
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002002void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002003 Register input = ToRegister(instr->InputAt(0));
2004 Register result = ToRegister(instr->result());
2005 Register scratch = scratch0();
2006
2007 ASSERT(instr->hydrogen()->value()->representation().IsTagged());
2008 __ ldr(scratch,
2009 FieldMemOperand(input, String::kHashFieldOffset));
2010 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
2011 __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
2012 __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002013}
2014
2015
2016void LCodeGen::DoHasCachedArrayIndexAndBranch(
2017 LHasCachedArrayIndexAndBranch* instr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002018 Register input = ToRegister(instr->InputAt(0));
2019 Register scratch = scratch0();
2020
2021 int true_block = chunk_->LookupDestination(instr->true_block_id());
2022 int false_block = chunk_->LookupDestination(instr->false_block_id());
2023
2024 __ ldr(scratch,
2025 FieldMemOperand(input, String::kHashFieldOffset));
2026 __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
2027 EmitBranch(true_block, false_block, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002028}
2029
2030
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002031// Branches to a label or falls through with the answer in flags. Trashes
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032// the temp registers, but not the input. Only input and temp2 may alias.
2033void LCodeGen::EmitClassOfTest(Label* is_true,
2034 Label* is_false,
2035 Handle<String>class_name,
2036 Register input,
2037 Register temp,
2038 Register temp2) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002039 ASSERT(!input.is(temp));
2040 ASSERT(!temp.is(temp2)); // But input and temp2 may be the same register.
2041 __ tst(input, Operand(kSmiTagMask));
2042 __ b(eq, is_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002043 __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002044 __ b(lt, is_false);
2045
2046 // Map is now in temp.
2047 // Functions have class 'Function'.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002048 __ CompareInstanceType(temp, temp2, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002049 if (class_name->IsEqualTo(CStrVector("Function"))) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002050 __ b(ge, is_true);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002051 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002052 __ b(ge, is_false);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002053 }
2054
2055 // Check if the constructor in the map is a function.
2056 __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset));
2057
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002058 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type and
2059 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2060 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2061 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2062 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2063 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002064
2065 // Objects with a non-function constructor have class 'Object'.
2066 __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
2067 if (class_name->IsEqualTo(CStrVector("Object"))) {
2068 __ b(ne, is_true);
2069 } else {
2070 __ b(ne, is_false);
2071 }
2072
2073 // temp now contains the constructor function. Grab the
2074 // instance class name from there.
2075 __ ldr(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset));
2076 __ ldr(temp, FieldMemOperand(temp,
2077 SharedFunctionInfo::kInstanceClassNameOffset));
2078 // The class name we are testing against is a symbol because it's a literal.
2079 // The name in the constructor is a symbol because of the way the context is
2080 // booted. This routine isn't expected to work for random API-created
2081 // classes and it doesn't have to because you can't access it with natives
2082 // syntax. Since both sides are symbols it is sufficient to use an identity
2083 // comparison.
2084 __ cmp(temp, Operand(class_name));
2085 // End with the answer in flags.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002086}
2087
2088
2089void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002090 Register input = ToRegister(instr->InputAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002091 Register result = ToRegister(instr->result());
2092 ASSERT(input.is(result));
2093 Handle<String> class_name = instr->hydrogen()->class_name();
2094
2095 Label done, is_true, is_false;
2096
2097 EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input);
2098 __ b(ne, &is_false);
2099
2100 __ bind(&is_true);
2101 __ LoadRoot(result, Heap::kTrueValueRootIndex);
2102 __ jmp(&done);
2103
2104 __ bind(&is_false);
2105 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2106 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002107}
2108
2109
2110void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002111 Register input = ToRegister(instr->InputAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002112 Register temp = scratch0();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002113 Register temp2 = ToRegister(instr->TempAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002114 Handle<String> class_name = instr->hydrogen()->class_name();
2115
2116 int true_block = chunk_->LookupDestination(instr->true_block_id());
2117 int false_block = chunk_->LookupDestination(instr->false_block_id());
2118
2119 Label* true_label = chunk_->GetAssemblyLabel(true_block);
2120 Label* false_label = chunk_->GetAssemblyLabel(false_block);
2121
2122 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2);
2123
2124 EmitBranch(true_block, false_block, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002125}
2126
2127
2128void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002129 Register reg = ToRegister(instr->InputAt(0));
2130 Register temp = ToRegister(instr->TempAt(0));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002131 int true_block = instr->true_block_id();
2132 int false_block = instr->false_block_id();
2133
2134 __ ldr(temp, FieldMemOperand(reg, HeapObject::kMapOffset));
2135 __ cmp(temp, Operand(instr->map()));
2136 EmitBranch(true_block, false_block, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002137}
2138
2139
2140void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002141 ASSERT(ToRegister(instr->InputAt(0)).is(r0)); // Object is in r0.
2142 ASSERT(ToRegister(instr->InputAt(1)).is(r1)); // Function is in r1.
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002143
whesse@chromium.org023421e2010-12-21 12:19:12 +00002144 InstanceofStub stub(InstanceofStub::kArgsInRegisters);
2145 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002147 __ cmp(r0, Operand(0));
2148 __ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
2149 __ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002150}
2151
2152
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002153void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002154 class DeferredInstanceOfKnownGlobal: public LDeferredCode {
2155 public:
2156 DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
2157 LInstanceOfKnownGlobal* instr)
2158 : LDeferredCode(codegen), instr_(instr) { }
2159 virtual void Generate() {
2160 codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
2161 }
2162
2163 Label* map_check() { return &map_check_; }
2164
2165 private:
2166 LInstanceOfKnownGlobal* instr_;
2167 Label map_check_;
2168 };
2169
2170 DeferredInstanceOfKnownGlobal* deferred;
2171 deferred = new DeferredInstanceOfKnownGlobal(this, instr);
2172
2173 Label done, false_result;
2174 Register object = ToRegister(instr->InputAt(0));
2175 Register temp = ToRegister(instr->TempAt(0));
2176 Register result = ToRegister(instr->result());
2177
2178 ASSERT(object.is(r0));
2179 ASSERT(result.is(r0));
2180
2181 // A Smi is not instance of anything.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002182 __ JumpIfSmi(object, &false_result);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002183
2184 // This is the inlined call site instanceof cache. The two occurences of the
2185 // hole value will be patched to the last map/result pair generated by the
2186 // instanceof stub.
2187 Label cache_miss;
2188 Register map = temp;
2189 __ ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
2190 __ bind(deferred->map_check()); // Label for calculating code patching.
2191 // We use Factory::the_hole_value() on purpose instead of loading from the
2192 // root array to force relocation to be able to later patch with
2193 // the cached map.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 __ mov(ip, Operand(factory()->the_hole_value()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002195 __ cmp(map, Operand(ip));
2196 __ b(ne, &cache_miss);
2197 // We use Factory::the_hole_value() on purpose instead of loading from the
2198 // root array to force relocation to be able to later patch
2199 // with true or false.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002200 __ mov(result, Operand(factory()->the_hole_value()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002201 __ b(&done);
2202
2203 // The inlined call site cache did not match. Check null and string before
2204 // calling the deferred code.
2205 __ bind(&cache_miss);
2206 // Null is not instance of anything.
2207 __ LoadRoot(ip, Heap::kNullValueRootIndex);
2208 __ cmp(object, Operand(ip));
2209 __ b(eq, &false_result);
2210
2211 // String values is not instance of anything.
2212 Condition is_string = masm_->IsObjectStringType(object, temp);
2213 __ b(is_string, &false_result);
2214
2215 // Go to the deferred code.
2216 __ b(deferred->entry());
2217
2218 __ bind(&false_result);
2219 __ LoadRoot(result, Heap::kFalseValueRootIndex);
2220
2221 // Here result has either true or false. Deferred code also produces true or
2222 // false object.
2223 __ bind(deferred->exit());
2224 __ bind(&done);
2225}
2226
2227
2228void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
2229 Label* map_check) {
2230 Register result = ToRegister(instr->result());
2231 ASSERT(result.is(r0));
2232
2233 InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
2234 flags = static_cast<InstanceofStub::Flags>(
2235 flags | InstanceofStub::kArgsInRegisters);
2236 flags = static_cast<InstanceofStub::Flags>(
2237 flags | InstanceofStub::kCallSiteInlineCheck);
2238 flags = static_cast<InstanceofStub::Flags>(
2239 flags | InstanceofStub::kReturnTrueFalseObject);
2240 InstanceofStub stub(flags);
2241
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002242 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002243
2244 // Get the temp register reserved by the instruction. This needs to be r4 as
2245 // its slot of the pushing of safepoint registers is used to communicate the
2246 // offset to the location of the map check.
2247 Register temp = ToRegister(instr->TempAt(0));
2248 ASSERT(temp.is(r4));
2249 __ mov(InstanceofStub::right(), Operand(instr->function()));
2250 static const int kAdditionalDelta = 4;
2251 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta;
2252 Label before_push_delta;
2253 __ bind(&before_push_delta);
2254 __ BlockConstPoolFor(kAdditionalDelta);
2255 __ mov(temp, Operand(delta * kPointerSize));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002256 __ StoreToSafepointRegisterSlot(temp, temp);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002257 CallCodeGeneric(stub.GetCode(),
2258 RelocInfo::CODE_TARGET,
2259 instr,
2260 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002261 // Put the result value into the result register slot and
2262 // restore all registers.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002263 __ StoreToSafepointRegisterSlot(result, result);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002264}
2265
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002266
2267static Condition ComputeCompareCondition(Token::Value op) {
2268 switch (op) {
2269 case Token::EQ_STRICT:
2270 case Token::EQ:
2271 return eq;
2272 case Token::LT:
2273 return lt;
2274 case Token::GT:
2275 return gt;
2276 case Token::LTE:
2277 return le;
2278 case Token::GTE:
2279 return ge;
2280 default:
2281 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00002282 return kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002283 }
2284}
2285
2286
2287void LCodeGen::DoCmpT(LCmpT* instr) {
2288 Token::Value op = instr->op();
2289
2290 Handle<Code> ic = CompareIC::GetUninitialized(op);
2291 CallCode(ic, RelocInfo::CODE_TARGET, instr);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002292 __ cmp(r0, Operand(0)); // This instruction also signals no smi code inlined.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293
2294 Condition condition = ComputeCompareCondition(op);
2295 if (op == Token::GT || op == Token::LTE) {
2296 condition = ReverseCondition(condition);
2297 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002298 __ LoadRoot(ToRegister(instr->result()),
2299 Heap::kTrueValueRootIndex,
2300 condition);
2301 __ LoadRoot(ToRegister(instr->result()),
2302 Heap::kFalseValueRootIndex,
2303 NegateCondition(condition));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002304}
2305
2306
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002307void LCodeGen::DoReturn(LReturn* instr) {
2308 if (FLAG_trace) {
2309 // Push the return value on the stack as the parameter.
2310 // Runtime::TraceExit returns its parameter in r0.
2311 __ push(r0);
2312 __ CallRuntime(Runtime::kTraceExit, 1);
2313 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00002314 int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002315 __ mov(sp, fp);
2316 __ ldm(ia_w, sp, fp.bit() | lr.bit());
2317 __ add(sp, sp, Operand(sp_delta));
2318 __ Jump(lr);
2319}
2320
2321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002322void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002323 Register result = ToRegister(instr->result());
2324 __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell())));
2325 __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
2326 if (instr->hydrogen()->check_hole_value()) {
2327 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
2328 __ cmp(result, ip);
2329 DeoptimizeIf(eq, instr->environment());
2330 }
2331}
2332
2333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002334void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
2335 ASSERT(ToRegister(instr->global_object()).is(r0));
2336 ASSERT(ToRegister(instr->result()).is(r0));
2337
2338 __ mov(r2, Operand(instr->name()));
2339 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET
2340 : RelocInfo::CODE_TARGET_CONTEXT;
2341 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2342 CallCode(ic, mode, instr);
2343}
2344
2345
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002346void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002347 Register value = ToRegister(instr->InputAt(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00002348 Register scratch = scratch0();
2349
2350 // Load the cell.
2351 __ mov(scratch, Operand(Handle<Object>(instr->hydrogen()->cell())));
2352
2353 // If the cell we are storing to contains the hole it could have
2354 // been deleted from the property dictionary. In that case, we need
2355 // to update the property details in the property dictionary to mark
2356 // it as no longer deleted.
2357 if (instr->hydrogen()->check_hole_value()) {
2358 Register scratch2 = ToRegister(instr->TempAt(0));
2359 __ ldr(scratch2,
2360 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
2361 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
2362 __ cmp(scratch2, ip);
2363 DeoptimizeIf(eq, instr->environment());
2364 }
2365
2366 // Store the value.
2367 __ str(value, FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002368}
2369
2370
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002371void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
2372 ASSERT(ToRegister(instr->global_object()).is(r1));
2373 ASSERT(ToRegister(instr->value()).is(r0));
2374
2375 __ mov(r2, Operand(instr->name()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002376 Handle<Code> ic = instr->strict_mode()
2377 ? isolate()->builtins()->StoreIC_Initialize_Strict()
2378 : isolate()->builtins()->StoreIC_Initialize();
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002379 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
2380}
2381
2382
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002383void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002384 Register context = ToRegister(instr->context());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002385 Register result = ToRegister(instr->result());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002386 __ ldr(result, ContextOperand(context, instr->slot_index()));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002387}
2388
2389
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002390void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
2391 Register context = ToRegister(instr->context());
2392 Register value = ToRegister(instr->value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002393 __ str(value, ContextOperand(context, instr->slot_index()));
2394 if (instr->needs_write_barrier()) {
2395 int offset = Context::SlotOffset(instr->slot_index());
2396 __ RecordWrite(context, Operand(offset), value, scratch0());
2397 }
2398}
2399
2400
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002401void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002402 Register object = ToRegister(instr->InputAt(0));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002403 Register result = ToRegister(instr->result());
2404 if (instr->hydrogen()->is_in_object()) {
2405 __ ldr(result, FieldMemOperand(object, instr->hydrogen()->offset()));
2406 } else {
2407 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2408 __ ldr(result, FieldMemOperand(result, instr->hydrogen()->offset()));
2409 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002410}
2411
2412
lrn@chromium.org1c092762011-05-09 09:42:16 +00002413void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
2414 Register object,
2415 Handle<Map> type,
2416 Handle<String> name) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002417 LookupResult lookup;
2418 type->LookupInDescriptors(NULL, *name, &lookup);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002419 ASSERT(lookup.IsProperty() &&
2420 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
2421 if (lookup.type() == FIELD) {
2422 int index = lookup.GetLocalFieldIndexFromMap(*type);
2423 int offset = index * kPointerSize;
2424 if (index < 0) {
2425 // Negative property indices are in-object properties, indexed
2426 // from the end of the fixed part of the object.
2427 __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
2428 } else {
2429 // Non-negative property indices are in the properties array.
2430 __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
2431 __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
2432 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002433 } else {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002434 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
2435 LoadHeapObject(result, Handle<HeapObject>::cast(function));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002436 }
2437}
2438
2439
2440void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
2441 Register object = ToRegister(instr->object());
2442 Register result = ToRegister(instr->result());
2443 Register scratch = scratch0();
2444 int map_count = instr->hydrogen()->types()->length();
2445 Handle<String> name = instr->hydrogen()->name();
2446 if (map_count == 0) {
2447 ASSERT(instr->hydrogen()->need_generic());
2448 __ mov(r2, Operand(name));
2449 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2450 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2451 } else {
2452 Label done;
2453 __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2454 for (int i = 0; i < map_count - 1; ++i) {
2455 Handle<Map> map = instr->hydrogen()->types()->at(i);
2456 Label next;
2457 __ cmp(scratch, Operand(map));
2458 __ b(ne, &next);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002459 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002460 __ b(&done);
2461 __ bind(&next);
2462 }
2463 Handle<Map> map = instr->hydrogen()->types()->last();
2464 __ cmp(scratch, Operand(map));
2465 if (instr->hydrogen()->need_generic()) {
2466 Label generic;
2467 __ b(ne, &generic);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002468 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002469 __ b(&done);
2470 __ bind(&generic);
2471 __ mov(r2, Operand(name));
2472 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2473 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2474 } else {
2475 DeoptimizeIf(ne, instr->environment());
lrn@chromium.org1c092762011-05-09 09:42:16 +00002476 EmitLoadFieldOrConstantFunction(result, object, map, name);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002477 }
2478 __ bind(&done);
2479 }
2480}
2481
2482
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
2484 ASSERT(ToRegister(instr->object()).is(r0));
2485 ASSERT(ToRegister(instr->result()).is(r0));
2486
2487 // Name is always in r2.
2488 __ mov(r2, Operand(instr->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002489 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002490 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2491}
2492
2493
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002494void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002495 Register scratch = scratch0();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002496 Register function = ToRegister(instr->function());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002497 Register result = ToRegister(instr->result());
2498
2499 // Check that the function really is a function. Load map into the
2500 // result register.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002501 __ CompareObjectType(function, result, scratch, JS_FUNCTION_TYPE);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002502 DeoptimizeIf(ne, instr->environment());
2503
2504 // Make sure that the function has an instance prototype.
2505 Label non_instance;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002506 __ ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
2507 __ tst(scratch, Operand(1 << Map::kHasNonInstancePrototype));
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002508 __ b(ne, &non_instance);
2509
2510 // Get the prototype or initial map from the function.
2511 __ ldr(result,
2512 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2513
2514 // Check that the function has a prototype or an initial map.
2515 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
2516 __ cmp(result, ip);
2517 DeoptimizeIf(eq, instr->environment());
2518
2519 // If the function does not have an initial map, we're done.
2520 Label done;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002521 __ CompareObjectType(result, scratch, scratch, MAP_TYPE);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00002522 __ b(ne, &done);
2523
2524 // Get the prototype from the initial map.
2525 __ ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
2526 __ jmp(&done);
2527
2528 // Non-instance prototype: Fetch prototype from constructor field
2529 // in initial map.
2530 __ bind(&non_instance);
2531 __ ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
2532
2533 // All done.
2534 __ bind(&done);
2535}
2536
2537
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002538void LCodeGen::DoLoadElements(LLoadElements* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002539 Register result = ToRegister(instr->result());
2540 Register input = ToRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002541 Register scratch = scratch0();
2542
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002543 __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002544 if (FLAG_debug_code) {
2545 Label done;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002546 __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002547 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
2548 __ cmp(scratch, ip);
2549 __ b(eq, &done);
2550 __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
2551 __ cmp(scratch, ip);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002552 __ b(eq, &done);
2553 __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
2554 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
2555 __ sub(scratch, scratch, Operand(FIRST_EXTERNAL_ARRAY_TYPE));
2556 __ cmp(scratch, Operand(kExternalArrayTypeCount));
2557 __ Check(cc, "Check for fast elements failed.");
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002558 __ bind(&done);
2559 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002560}
2561
2562
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002563void LCodeGen::DoLoadExternalArrayPointer(
2564 LLoadExternalArrayPointer* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002565 Register to_reg = ToRegister(instr->result());
2566 Register from_reg = ToRegister(instr->InputAt(0));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002567 __ ldr(to_reg, FieldMemOperand(from_reg,
2568 ExternalArray::kExternalPointerOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002569}
2570
2571
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002572void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002573 Register arguments = ToRegister(instr->arguments());
2574 Register length = ToRegister(instr->length());
2575 Register index = ToRegister(instr->index());
2576 Register result = ToRegister(instr->result());
2577
2578 // Bailout index is not a valid argument index. Use unsigned check to get
2579 // negative check for free.
2580 __ sub(length, length, index, SetCC);
2581 DeoptimizeIf(ls, instr->environment());
2582
2583 // There are two words between the frame pointer and the last argument.
2584 // Subtracting from length accounts for one of them add one more.
2585 __ add(length, length, Operand(1));
2586 __ ldr(result, MemOperand(arguments, length, LSL, kPointerSizeLog2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002587}
2588
2589
2590void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002591 Register elements = ToRegister(instr->elements());
2592 Register key = EmitLoadRegister(instr->key(), scratch0());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002593 Register result = ToRegister(instr->result());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002594 Register scratch = scratch0();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002595 ASSERT(result.is(elements));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002596
2597 // Load the result.
2598 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
2599 __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize));
2600
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002601 // Check for the hole value.
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002602 if (instr->hydrogen()->RequiresHoleCheck()) {
2603 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
2604 __ cmp(result, scratch);
2605 DeoptimizeIf(eq, instr->environment());
2606 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002607}
2608
2609
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002610void LCodeGen::DoLoadKeyedSpecializedArrayElement(
2611 LLoadKeyedSpecializedArrayElement* instr) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002612 Register external_pointer = ToRegister(instr->external_pointer());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002613 Register key = no_reg;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002614 JSObject::ElementsKind elements_kind = instr->elements_kind();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002615 bool key_is_constant = instr->key()->IsConstantOperand();
2616 int constant_key = 0;
2617 if (key_is_constant) {
2618 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
2619 if (constant_key & 0xF0000000) {
2620 Abort("array index constant value too big.");
2621 }
2622 } else {
2623 key = ToRegister(instr->key());
2624 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002625 int shift_size = ElementsKindToShiftSize(elements_kind);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002626
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002627 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
2628 elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00002629 CpuFeatures::Scope scope(VFP3);
2630 DwVfpRegister result(ToDoubleRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002631 Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
2632 : Operand(key, LSL, shift_size));
2633 __ add(scratch0(), external_pointer, operand);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002634 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002635 __ vldr(result.low(), scratch0(), 0);
2636 __ vcvt_f64_f32(result, result.low());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002637 } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002638 __ vldr(result, scratch0(), 0);
2639 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002640 } else {
2641 Register result(ToRegister(instr->result()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002642 MemOperand mem_operand(key_is_constant
2643 ? MemOperand(external_pointer, constant_key * (1 << shift_size))
2644 : MemOperand(external_pointer, key, LSL, shift_size));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002645 switch (elements_kind) {
2646 case JSObject::EXTERNAL_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002647 __ ldrsb(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002648 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002649 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
2650 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002651 __ ldrb(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002652 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002653 case JSObject::EXTERNAL_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002654 __ ldrsh(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002655 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002656 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002657 __ ldrh(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002658 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002659 case JSObject::EXTERNAL_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002660 __ ldr(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002661 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002662 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002663 __ ldr(result, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002664 __ cmp(result, Operand(0x80000000));
2665 // TODO(danno): we could be more clever here, perhaps having a special
2666 // version of the stub that detects if the overflow case actually
2667 // happens, and generate code that returns a double rather than int.
2668 DeoptimizeIf(cs, instr->environment());
2669 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002670 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
2671 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
2672 case JSObject::FAST_DOUBLE_ELEMENTS:
2673 case JSObject::FAST_ELEMENTS:
2674 case JSObject::DICTIONARY_ELEMENTS:
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002675 UNREACHABLE();
2676 break;
2677 }
2678 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002679}
2680
2681
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002682void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
2683 ASSERT(ToRegister(instr->object()).is(r1));
2684 ASSERT(ToRegister(instr->key()).is(r0));
2685
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002686 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002687 CallCode(ic, RelocInfo::CODE_TARGET, instr);
2688}
2689
2690
2691void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002692 Register scratch = scratch0();
2693 Register result = ToRegister(instr->result());
2694
2695 // Check if the calling frame is an arguments adaptor frame.
2696 Label done, adapted;
2697 __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2698 __ ldr(result, MemOperand(scratch, StandardFrameConstants::kContextOffset));
2699 __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2700
2701 // Result is the frame pointer for the frame if not adapted and for the real
2702 // frame below the adaptor frame if adapted.
2703 __ mov(result, fp, LeaveCC, ne);
2704 __ mov(result, scratch, LeaveCC, eq);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002705}
2706
2707
2708void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002709 Register elem = ToRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002710 Register result = ToRegister(instr->result());
2711
2712 Label done;
2713
2714 // If no arguments adaptor frame the number of arguments is fixed.
2715 __ cmp(fp, elem);
2716 __ mov(result, Operand(scope()->num_parameters()));
2717 __ b(eq, &done);
2718
2719 // Arguments adaptor frame present. Get argument length from there.
2720 __ ldr(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2721 __ ldr(result,
2722 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset));
2723 __ SmiUntag(result);
2724
2725 // Argument length is in result register.
2726 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727}
2728
2729
2730void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002731 Register receiver = ToRegister(instr->receiver());
2732 Register function = ToRegister(instr->function());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002733 Register length = ToRegister(instr->length());
2734 Register elements = ToRegister(instr->elements());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002735 Register scratch = scratch0();
2736 ASSERT(receiver.is(r0)); // Used for parameter count.
2737 ASSERT(function.is(r1)); // Required by InvokeFunction.
2738 ASSERT(ToRegister(instr->result()).is(r0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002739
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002740 // If the receiver is null or undefined, we have to pass the global
2741 // object as a receiver to normal functions. Values have to be
2742 // passed unchanged to builtins and strict-mode functions.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002743 Label global_object, receiver_ok;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002744
2745 // Do not transform the receiver to object for strict mode
2746 // functions.
2747 __ ldr(scratch,
2748 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
2749 __ ldr(scratch,
2750 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
2751 __ tst(scratch,
2752 Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize)));
2753 __ b(ne, &receiver_ok);
2754
2755 // Do not transform the receiver to object for builtins.
2756 __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
2757 __ b(ne, &receiver_ok);
2758
2759 // Normal function. Replace undefined or null with global receiver.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002760 __ LoadRoot(scratch, Heap::kNullValueRootIndex);
2761 __ cmp(receiver, scratch);
2762 __ b(eq, &global_object);
2763 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
2764 __ cmp(receiver, scratch);
2765 __ b(eq, &global_object);
2766
2767 // Deoptimize if the receiver is not a JS object.
2768 __ tst(receiver, Operand(kSmiTagMask));
2769 DeoptimizeIf(eq, instr->environment());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002770 __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
2771 DeoptimizeIf(lt, instr->environment());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002772 __ jmp(&receiver_ok);
2773
2774 __ bind(&global_object);
2775 __ ldr(receiver, GlobalObjectOperand());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002776 __ ldr(receiver,
2777 FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002778 __ bind(&receiver_ok);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002779
2780 // Copy the arguments to this function possibly from the
2781 // adaptor frame below it.
2782 const uint32_t kArgumentsLimit = 1 * KB;
2783 __ cmp(length, Operand(kArgumentsLimit));
2784 DeoptimizeIf(hi, instr->environment());
2785
2786 // Push the receiver and use the register to keep the original
2787 // number of arguments.
2788 __ push(receiver);
2789 __ mov(receiver, length);
2790 // The arguments are at a one pointer size offset from elements.
2791 __ add(elements, elements, Operand(1 * kPointerSize));
2792
2793 // Loop through the arguments pushing them onto the execution
2794 // stack.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002795 Label invoke, loop;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002796 // length is a small non-negative integer, due to the test above.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002797 __ cmp(length, Operand(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002798 __ b(eq, &invoke);
2799 __ bind(&loop);
2800 __ ldr(scratch, MemOperand(elements, length, LSL, 2));
2801 __ push(scratch);
2802 __ sub(length, length, Operand(1), SetCC);
2803 __ b(ne, &loop);
2804
2805 __ bind(&invoke);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002806 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2807 LPointerMap* pointers = instr->pointer_map();
2808 LEnvironment* env = instr->deoptimization_environment();
2809 RecordPosition(pointers->position());
2810 RegisterEnvironmentForDeoptimization(env);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002811 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00002812 pointers,
2813 env->deoptimization_index());
2814 // The number of arguments is stored in receiver which is r0, as expected
2815 // by InvokeFunction.
2816 v8::internal::ParameterCount actual(receiver);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002817 __ InvokeFunction(function, actual, CALL_FUNCTION,
2818 safepoint_generator, CALL_AS_METHOD);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00002819 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002820}
2821
2822
2823void LCodeGen::DoPushArgument(LPushArgument* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002824 LOperand* argument = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) {
2826 Abort("DoPushArgument not implemented for double type.");
2827 } else {
2828 Register argument_reg = EmitLoadRegister(argument, ip);
2829 __ push(argument_reg);
2830 }
2831}
2832
2833
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002834void LCodeGen::DoThisFunction(LThisFunction* instr) {
2835 Register result = ToRegister(instr->result());
2836 __ ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
2837}
2838
2839
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002840void LCodeGen::DoContext(LContext* instr) {
2841 Register result = ToRegister(instr->result());
2842 __ mov(result, cp);
2843}
2844
2845
2846void LCodeGen::DoOuterContext(LOuterContext* instr) {
2847 Register context = ToRegister(instr->context());
2848 Register result = ToRegister(instr->result());
2849 __ ldr(result,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002850 MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002851}
2852
2853
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002854void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002855 Register context = ToRegister(instr->context());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002856 Register result = ToRegister(instr->result());
2857 __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
2858}
2859
2860
2861void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002862 Register global = ToRegister(instr->global());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863 Register result = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002864 __ ldr(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002865}
2866
2867
2868void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2869 int arity,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002870 LInstruction* instr,
2871 CallKind call_kind) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002872 // Change context if needed.
2873 bool change_context =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002874 (info()->closure()->context() != function->context()) ||
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002875 scope()->contains_with() ||
2876 (scope()->num_heap_slots() > 0);
2877 if (change_context) {
2878 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
2879 }
2880
2881 // Set r0 to arguments count if adaption is not needed. Assumes that r0
2882 // is available to write to at this point.
2883 if (!function->NeedsArgumentsAdaption()) {
2884 __ mov(r0, Operand(arity));
2885 }
2886
2887 LPointerMap* pointers = instr->pointer_map();
2888 RecordPosition(pointers->position());
2889
2890 // Invoke function.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002891 __ SetCallKind(r5, call_kind);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002892 __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2893 __ Call(ip);
2894
2895 // Setup deoptimization.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002896 RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002897
2898 // Restore context.
2899 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2900}
2901
2902
2903void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00002904 ASSERT(ToRegister(instr->result()).is(r0));
2905 __ mov(r1, Operand(instr->function()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00002906 CallKnownFunction(instr->function(),
2907 instr->arity(),
2908 instr,
2909 CALL_AS_METHOD);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002910}
2911
2912
2913void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002914 ASSERT(instr->InputAt(0)->Equals(instr->result()));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002915 Register input = ToRegister(instr->InputAt(0));
2916 Register scratch = scratch0();
2917
2918 // Deoptimize if not a heap number.
2919 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
2920 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
2921 __ cmp(scratch, Operand(ip));
2922 DeoptimizeIf(ne, instr->environment());
2923
2924 Label done;
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002925 Register exponent = scratch0();
2926 scratch = no_reg;
2927 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002928 // Check the sign of the argument. If the argument is positive, just
2929 // return it. We do not need to patch the stack since |input| and
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002930 // |result| are the same register and |input| would be restored
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002931 // unchanged by popping safepoint registers.
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002932 __ tst(exponent, Operand(HeapNumber::kSignMask));
2933 __ b(eq, &done);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002934
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002935 // Input is negative. Reverse its sign.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002936 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002937 {
2938 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002939
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002940 // Registers were saved at the safepoint, so we can use
2941 // many scratch registers.
2942 Register tmp1 = input.is(r1) ? r0 : r1;
2943 Register tmp2 = input.is(r2) ? r0 : r2;
2944 Register tmp3 = input.is(r3) ? r0 : r3;
2945 Register tmp4 = input.is(r4) ? r0 : r4;
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002946
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002947 // exponent: floating point exponent value.
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002948
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002949 Label allocated, slow;
2950 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex);
2951 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow);
2952 __ b(&allocated);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002953
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002954 // Slow case: Call the runtime system to do the number allocation.
2955 __ bind(&slow);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002956
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002957 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
2958 // Set the pointer to the new heap number in tmp.
2959 if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0));
2960 // Restore input_reg after call to runtime.
2961 __ LoadFromSafepointRegisterSlot(input, input);
2962 __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002963
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002964 __ bind(&allocated);
2965 // exponent: floating point exponent value.
2966 // tmp1: allocated heap number.
2967 __ bic(exponent, exponent, Operand(HeapNumber::kSignMask));
2968 __ str(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset));
2969 __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
2970 __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002971
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002972 __ StoreToSafepointRegisterSlot(tmp1, input);
2973 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002974
2975 __ bind(&done);
2976}
2977
2978
2979void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002980 Register input = ToRegister(instr->InputAt(0));
whesse@chromium.org7a392b32011-01-31 11:30:36 +00002981 __ cmp(input, Operand(0));
2982 // We can make rsb conditional because the previous cmp instruction
2983 // will clear the V (overflow) flag and rsb won't set this flag
2984 // if input is positive.
2985 __ rsb(input, input, Operand(0), SetCC, mi);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002986 // Deoptimize on overflow.
2987 DeoptimizeIf(vs, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002988}
2989
2990
2991void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002992 // Class for deferred case.
2993 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode {
2994 public:
2995 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen,
2996 LUnaryMathOperation* instr)
2997 : LDeferredCode(codegen), instr_(instr) { }
2998 virtual void Generate() {
2999 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_);
3000 }
3001 private:
3002 LUnaryMathOperation* instr_;
3003 };
3004
3005 ASSERT(instr->InputAt(0)->Equals(instr->result()));
3006 Representation r = instr->hydrogen()->value()->representation();
3007 if (r.IsDouble()) {
3008 DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003009 __ vabs(input, input);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003010 } else if (r.IsInteger32()) {
3011 EmitIntegerMathAbs(instr);
3012 } else {
3013 // Representation is tagged.
3014 DeferredMathAbsTaggedHeapNumber* deferred =
3015 new DeferredMathAbsTaggedHeapNumber(this, instr);
3016 Register input = ToRegister(instr->InputAt(0));
3017 // Smi check.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003018 __ JumpIfNotSmi(input, deferred->entry());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003019 // If smi, handle it directly.
3020 EmitIntegerMathAbs(instr);
3021 __ bind(deferred->exit());
3022 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003023}
3024
3025
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003026void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
3027 DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
3028 Register result = ToRegister(instr->result());
3029 SwVfpRegister single_scratch = double_scratch0().low();
3030 Register scratch1 = scratch0();
3031 Register scratch2 = ToRegister(instr->TempAt(0));
3032
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003033 __ EmitVFPTruncate(kRoundToMinusInf,
3034 single_scratch,
3035 input,
3036 scratch1,
3037 scratch2);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003038 DeoptimizeIf(ne, instr->environment());
3039
3040 // Move the result back to general purpose register r0.
3041 __ vmov(result, single_scratch);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00003042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003043 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3044 // Test for -0.
3045 Label done;
3046 __ cmp(result, Operand(0));
3047 __ b(ne, &done);
3048 __ vmov(scratch1, input.high());
3049 __ tst(scratch1, Operand(HeapNumber::kSignMask));
3050 DeoptimizeIf(ne, instr->environment());
3051 __ bind(&done);
3052 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003053}
3054
3055
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003056void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
3057 DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
3058 Register result = ToRegister(instr->result());
danno@chromium.org160a7b02011-04-18 15:51:38 +00003059 Register scratch1 = result;
3060 Register scratch2 = scratch0();
3061 Label done, check_sign_on_zero;
3062
3063 // Extract exponent bits.
3064 __ vmov(scratch1, input.high());
3065 __ ubfx(scratch2,
3066 scratch1,
3067 HeapNumber::kExponentShift,
3068 HeapNumber::kExponentBits);
3069
3070 // If the number is in ]-0.5, +0.5[, the result is +/- 0.
3071 __ cmp(scratch2, Operand(HeapNumber::kExponentBias - 2));
3072 __ mov(result, Operand(0), LeaveCC, le);
3073 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3074 __ b(le, &check_sign_on_zero);
3075 } else {
3076 __ b(le, &done);
3077 }
3078
3079 // The following conversion will not work with numbers
3080 // outside of ]-2^32, 2^32[.
3081 __ cmp(scratch2, Operand(HeapNumber::kExponentBias + 32));
3082 DeoptimizeIf(ge, instr->environment());
3083
3084 // Save the original sign for later comparison.
3085 __ and_(scratch2, scratch1, Operand(HeapNumber::kSignMask));
3086
3087 __ vmov(double_scratch0(), 0.5);
3088 __ vadd(input, input, double_scratch0());
3089
3090 // Check sign of the result: if the sign changed, the input
3091 // value was in ]0.5, 0[ and the result should be -0.
3092 __ vmov(scratch1, input.high());
3093 __ eor(scratch1, scratch1, Operand(scratch2), SetCC);
3094 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3095 DeoptimizeIf(mi, instr->environment());
3096 } else {
3097 __ mov(result, Operand(0), LeaveCC, mi);
3098 __ b(mi, &done);
3099 }
3100
3101 __ EmitVFPTruncate(kRoundToMinusInf,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003102 double_scratch0().low(),
3103 input,
3104 scratch1,
3105 scratch2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003106 DeoptimizeIf(ne, instr->environment());
3107 __ vmov(result, double_scratch0().low());
3108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003109 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3110 // Test for -0.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003111 __ cmp(result, Operand(0));
3112 __ b(ne, &done);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003113 __ bind(&check_sign_on_zero);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 __ vmov(scratch1, input.high());
3115 __ tst(scratch1, Operand(HeapNumber::kSignMask));
3116 DeoptimizeIf(ne, instr->environment());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003117 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003118 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003119}
3120
3121
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003122void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003123 DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003124 ASSERT(ToDoubleRegister(instr->result()).is(input));
3125 __ vsqrt(input, input);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003126}
3127
3128
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003129void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
3130 DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
3131 Register scratch = scratch0();
3132 SwVfpRegister single_scratch = double_scratch0().low();
3133 DoubleRegister double_scratch = double_scratch0();
3134 ASSERT(ToDoubleRegister(instr->result()).is(input));
3135
3136 // Add +0 to convert -0 to +0.
3137 __ mov(scratch, Operand(0));
3138 __ vmov(single_scratch, scratch);
3139 __ vcvt_f64_s32(double_scratch, single_scratch);
3140 __ vadd(input, input, double_scratch);
3141 __ vsqrt(input, input);
3142}
3143
3144
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003145void LCodeGen::DoPower(LPower* instr) {
3146 LOperand* left = instr->InputAt(0);
3147 LOperand* right = instr->InputAt(1);
3148 Register scratch = scratch0();
3149 DoubleRegister result_reg = ToDoubleRegister(instr->result());
3150 Representation exponent_type = instr->hydrogen()->right()->representation();
3151 if (exponent_type.IsDouble()) {
3152 // Prepare arguments and call C function.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003153 __ PrepareCallCFunction(0, 2, scratch);
3154 __ SetCallCDoubleArguments(ToDoubleRegister(left),
3155 ToDoubleRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 __ CallCFunction(
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003157 ExternalReference::power_double_double_function(isolate()), 0, 2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003158 } else if (exponent_type.IsInteger32()) {
3159 ASSERT(ToRegister(right).is(r0));
3160 // Prepare arguments and call C function.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003161 __ PrepareCallCFunction(1, 1, scratch);
3162 __ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003163 __ CallCFunction(
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003164 ExternalReference::power_double_int_function(isolate()), 1, 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003165 } else {
3166 ASSERT(exponent_type.IsTagged());
3167 ASSERT(instr->hydrogen()->left()->representation().IsDouble());
3168
3169 Register right_reg = ToRegister(right);
3170
3171 // Check for smi on the right hand side.
3172 Label non_smi, call;
3173 __ JumpIfNotSmi(right_reg, &non_smi);
3174
3175 // Untag smi and convert it to a double.
3176 __ SmiUntag(right_reg);
3177 SwVfpRegister single_scratch = double_scratch0().low();
3178 __ vmov(single_scratch, right_reg);
3179 __ vcvt_f64_s32(result_reg, single_scratch);
3180 __ jmp(&call);
3181
3182 // Heap number map check.
3183 __ bind(&non_smi);
3184 __ ldr(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset));
3185 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3186 __ cmp(scratch, Operand(ip));
3187 DeoptimizeIf(ne, instr->environment());
3188 int32_t value_offset = HeapNumber::kValueOffset - kHeapObjectTag;
3189 __ add(scratch, right_reg, Operand(value_offset));
3190 __ vldr(result_reg, scratch, 0);
3191
3192 // Prepare arguments and call C function.
3193 __ bind(&call);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003194 __ PrepareCallCFunction(0, 2, scratch);
3195 __ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 __ CallCFunction(
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003197 ExternalReference::power_double_double_function(isolate()), 0, 2);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003198 }
3199 // Store the result in the result register.
3200 __ GetCFunctionDoubleResult(result_reg);
3201}
3202
3203
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003204void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
3205 ASSERT(ToDoubleRegister(instr->result()).is(d2));
3206 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3207 TranscendentalCacheStub::UNTAGGED);
3208 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3209}
3210
3211
3212void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
3213 ASSERT(ToDoubleRegister(instr->result()).is(d2));
3214 TranscendentalCacheStub stub(TranscendentalCache::COS,
3215 TranscendentalCacheStub::UNTAGGED);
3216 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3217}
3218
3219
3220void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
3221 ASSERT(ToDoubleRegister(instr->result()).is(d2));
3222 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3223 TranscendentalCacheStub::UNTAGGED);
3224 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3225}
3226
3227
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003228void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003229 switch (instr->op()) {
3230 case kMathAbs:
3231 DoMathAbs(instr);
3232 break;
3233 case kMathFloor:
3234 DoMathFloor(instr);
3235 break;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003236 case kMathRound:
3237 DoMathRound(instr);
3238 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003239 case kMathSqrt:
3240 DoMathSqrt(instr);
3241 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003242 case kMathPowHalf:
3243 DoMathPowHalf(instr);
3244 break;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003245 case kMathCos:
3246 DoMathCos(instr);
3247 break;
3248 case kMathSin:
3249 DoMathSin(instr);
3250 break;
3251 case kMathLog:
3252 DoMathLog(instr);
3253 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003254 default:
whesse@chromium.org023421e2010-12-21 12:19:12 +00003255 Abort("Unimplemented type of LUnaryMathOperation.");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003256 UNREACHABLE();
3257 }
3258}
3259
3260
danno@chromium.org160a7b02011-04-18 15:51:38 +00003261void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
3262 ASSERT(ToRegister(instr->function()).is(r1));
3263 ASSERT(instr->HasPointerMap());
3264 ASSERT(instr->HasDeoptimizationEnvironment());
3265 LPointerMap* pointers = instr->pointer_map();
3266 LEnvironment* env = instr->deoptimization_environment();
3267 RecordPosition(pointers->position());
3268 RegisterEnvironmentForDeoptimization(env);
3269 SafepointGenerator generator(this, pointers, env->deoptimization_index());
3270 ParameterCount count(instr->arity());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003271 __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
danno@chromium.org160a7b02011-04-18 15:51:38 +00003272 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3273}
3274
3275
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003276void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003277 ASSERT(ToRegister(instr->result()).is(r0));
3278
3279 int arity = instr->arity();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003280 Handle<Code> ic =
3281 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003282 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3283 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003284}
3285
3286
3287void LCodeGen::DoCallNamed(LCallNamed* instr) {
3288 ASSERT(ToRegister(instr->result()).is(r0));
3289
3290 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003291 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
3292 Handle<Code> ic =
3293 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003294 __ mov(r2, Operand(instr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003295 CallCode(ic, mode, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003296 // Restore context register.
3297 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3298}
3299
3300
3301void LCodeGen::DoCallFunction(LCallFunction* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003302 ASSERT(ToRegister(instr->result()).is(r0));
3303
3304 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003305 CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_IMPLICIT);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003306 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3307 __ Drop(1);
3308 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003309}
3310
3311
3312void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003313 ASSERT(ToRegister(instr->result()).is(r0));
3314
3315 int arity = instr->arity();
danno@chromium.org40cb8782011-05-25 07:58:50 +00003316 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003317 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00003318 isolate()->stub_cache()->ComputeCallInitialize(arity, NOT_IN_LOOP, mode);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003319 __ mov(r2, Operand(instr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003320 CallCode(ic, mode, instr);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003321 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003322}
3323
3324
3325void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
3326 ASSERT(ToRegister(instr->result()).is(r0));
3327 __ mov(r1, Operand(instr->target()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003328 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003329}
3330
3331
3332void LCodeGen::DoCallNew(LCallNew* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003333 ASSERT(ToRegister(instr->InputAt(0)).is(r1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003334 ASSERT(ToRegister(instr->result()).is(r0));
3335
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003336 Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003337 __ mov(r0, Operand(instr->arity()));
3338 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
3339}
3340
3341
3342void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
3343 CallRuntime(instr->function(), instr->arity(), instr);
3344}
3345
3346
3347void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003348 Register object = ToRegister(instr->object());
3349 Register value = ToRegister(instr->value());
3350 Register scratch = scratch0();
3351 int offset = instr->offset();
3352
3353 ASSERT(!object.is(value));
3354
3355 if (!instr->transition().is_null()) {
3356 __ mov(scratch, Operand(instr->transition()));
3357 __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
3358 }
3359
3360 // Do the store.
3361 if (instr->is_in_object()) {
3362 __ str(value, FieldMemOperand(object, offset));
3363 if (instr->needs_write_barrier()) {
3364 // Update the write barrier for the object for in-object properties.
3365 __ RecordWrite(object, Operand(offset), value, scratch);
3366 }
3367 } else {
3368 __ ldr(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset));
3369 __ str(value, FieldMemOperand(scratch, offset));
3370 if (instr->needs_write_barrier()) {
3371 // Update the write barrier for the properties array.
3372 // object is used as a scratch register.
3373 __ RecordWrite(scratch, Operand(offset), value, object);
3374 }
3375 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003376}
3377
3378
3379void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
3380 ASSERT(ToRegister(instr->object()).is(r1));
3381 ASSERT(ToRegister(instr->value()).is(r0));
3382
3383 // Name is always in r2.
3384 __ mov(r2, Operand(instr->name()));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003385 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003386 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3387 : isolate()->builtins()->StoreIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003388 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3389}
3390
3391
3392void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003393 __ cmp(ToRegister(instr->index()), ToRegister(instr->length()));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003394 DeoptimizeIf(hs, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003395}
3396
3397
3398void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003399 Register value = ToRegister(instr->value());
3400 Register elements = ToRegister(instr->object());
3401 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg;
3402 Register scratch = scratch0();
3403
3404 // Do the store.
3405 if (instr->key()->IsConstantOperand()) {
3406 ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
3407 LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
3408 int offset =
3409 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
3410 __ str(value, FieldMemOperand(elements, offset));
3411 } else {
3412 __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
3413 __ str(value, FieldMemOperand(scratch, FixedArray::kHeaderSize));
3414 }
3415
3416 if (instr->hydrogen()->NeedsWriteBarrier()) {
3417 // Compute address of modified element and store it into key register.
3418 __ add(key, scratch, Operand(FixedArray::kHeaderSize));
3419 __ RecordWrite(elements, key, value);
3420 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003421}
3422
3423
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003424void LCodeGen::DoStoreKeyedSpecializedArrayElement(
3425 LStoreKeyedSpecializedArrayElement* instr) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003426
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003427 Register external_pointer = ToRegister(instr->external_pointer());
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003428 Register key = no_reg;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003429 JSObject::ElementsKind elements_kind = instr->elements_kind();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003430 bool key_is_constant = instr->key()->IsConstantOperand();
3431 int constant_key = 0;
3432 if (key_is_constant) {
3433 constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
3434 if (constant_key & 0xF0000000) {
3435 Abort("array index constant value too big.");
3436 }
3437 } else {
3438 key = ToRegister(instr->key());
3439 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003440 int shift_size = ElementsKindToShiftSize(elements_kind);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003441
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003442 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS ||
3443 elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00003444 CpuFeatures::Scope scope(VFP3);
3445 DwVfpRegister value(ToDoubleRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003446 Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
3447 : Operand(key, LSL, shift_size));
3448 __ add(scratch0(), external_pointer, operand);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003449 if (elements_kind == JSObject::EXTERNAL_FLOAT_ELEMENTS) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003450 __ vcvt_f32_f64(double_scratch0().low(), value);
3451 __ vstr(double_scratch0().low(), scratch0(), 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003452 } else { // i.e. elements_kind == JSObject::EXTERNAL_DOUBLE_ELEMENTS
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003453 __ vstr(value, scratch0(), 0);
3454 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003455 } else {
3456 Register value(ToRegister(instr->value()));
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003457 MemOperand mem_operand(key_is_constant
3458 ? MemOperand(external_pointer, constant_key * (1 << shift_size))
3459 : MemOperand(external_pointer, key, LSL, shift_size));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003460 switch (elements_kind) {
3461 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
3462 case JSObject::EXTERNAL_BYTE_ELEMENTS:
3463 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003464 __ strb(value, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003465 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003466 case JSObject::EXTERNAL_SHORT_ELEMENTS:
3467 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003468 __ strh(value, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003469 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003470 case JSObject::EXTERNAL_INT_ELEMENTS:
3471 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00003472 __ str(value, mem_operand);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003473 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003474 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
3475 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
3476 case JSObject::FAST_DOUBLE_ELEMENTS:
3477 case JSObject::FAST_ELEMENTS:
3478 case JSObject::DICTIONARY_ELEMENTS:
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003479 UNREACHABLE();
3480 break;
3481 }
3482 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003483}
3484
3485
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003486void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
3487 ASSERT(ToRegister(instr->object()).is(r2));
3488 ASSERT(ToRegister(instr->key()).is(r1));
3489 ASSERT(ToRegister(instr->value()).is(r0));
3490
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003491 Handle<Code> ic = instr->strict_mode()
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003492 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3493 : isolate()->builtins()->KeyedStoreIC_Initialize();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003494 CallCode(ic, RelocInfo::CODE_TARGET, instr);
3495}
3496
3497
danno@chromium.org160a7b02011-04-18 15:51:38 +00003498void LCodeGen::DoStringAdd(LStringAdd* instr) {
3499 __ push(ToRegister(instr->left()));
3500 __ push(ToRegister(instr->right()));
3501 StringAddStub stub(NO_STRING_CHECK_IN_STUB);
3502 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3503}
3504
3505
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003506void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
3507 class DeferredStringCharCodeAt: public LDeferredCode {
3508 public:
3509 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
3510 : LDeferredCode(codegen), instr_(instr) { }
3511 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
3512 private:
3513 LStringCharCodeAt* instr_;
3514 };
3515
3516 Register scratch = scratch0();
3517 Register string = ToRegister(instr->string());
3518 Register index = no_reg;
3519 int const_index = -1;
3520 if (instr->index()->IsConstantOperand()) {
3521 const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3522 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
3523 if (!Smi::IsValid(const_index)) {
3524 // Guaranteed to be out of bounds because of the assert above.
3525 // So the bounds check that must dominate this instruction must
3526 // have deoptimized already.
3527 if (FLAG_debug_code) {
3528 __ Abort("StringCharCodeAt: out of bounds index.");
3529 }
3530 // No code needs to be generated.
3531 return;
3532 }
3533 } else {
3534 index = ToRegister(instr->index());
3535 }
3536 Register result = ToRegister(instr->result());
3537
3538 DeferredStringCharCodeAt* deferred =
3539 new DeferredStringCharCodeAt(this, instr);
3540
3541 Label flat_string, ascii_string, done;
3542
3543 // Fetch the instance type of the receiver into result register.
3544 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
3545 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
3546
3547 // We need special handling for non-flat strings.
3548 STATIC_ASSERT(kSeqStringTag == 0);
3549 __ tst(result, Operand(kStringRepresentationMask));
3550 __ b(eq, &flat_string);
3551
3552 // Handle non-flat strings.
3553 __ tst(result, Operand(kIsConsStringMask));
3554 __ b(eq, deferred->entry());
3555
3556 // ConsString.
3557 // Check whether the right hand side is the empty string (i.e. if
3558 // this is really a flat string in a cons string). If that is not
3559 // the case we would rather go to the runtime system now to flatten
3560 // the string.
3561 __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset));
3562 __ LoadRoot(ip, Heap::kEmptyStringRootIndex);
3563 __ cmp(scratch, ip);
3564 __ b(ne, deferred->entry());
3565 // Get the first of the two strings and load its instance type.
3566 __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
3567 __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
3568 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
3569 // If the first cons component is also non-flat, then go to runtime.
3570 STATIC_ASSERT(kSeqStringTag == 0);
3571 __ tst(result, Operand(kStringRepresentationMask));
3572 __ b(ne, deferred->entry());
3573
3574 // Check for 1-byte or 2-byte string.
3575 __ bind(&flat_string);
3576 STATIC_ASSERT(kAsciiStringTag != 0);
3577 __ tst(result, Operand(kStringEncodingMask));
3578 __ b(ne, &ascii_string);
3579
3580 // 2-byte string.
3581 // Load the 2-byte character code into the result register.
3582 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3583 if (instr->index()->IsConstantOperand()) {
3584 __ ldrh(result,
3585 FieldMemOperand(string,
3586 SeqTwoByteString::kHeaderSize + 2 * const_index));
3587 } else {
3588 __ add(scratch,
3589 string,
3590 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3591 __ ldrh(result, MemOperand(scratch, index, LSL, 1));
3592 }
3593 __ jmp(&done);
3594
3595 // ASCII string.
3596 // Load the byte into the result register.
3597 __ bind(&ascii_string);
3598 if (instr->index()->IsConstantOperand()) {
3599 __ ldrb(result, FieldMemOperand(string,
3600 SeqAsciiString::kHeaderSize + const_index));
3601 } else {
3602 __ add(scratch,
3603 string,
3604 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3605 __ ldrb(result, MemOperand(scratch, index));
3606 }
3607 __ bind(&done);
3608 __ bind(deferred->exit());
3609}
3610
3611
3612void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
3613 Register string = ToRegister(instr->string());
3614 Register result = ToRegister(instr->result());
3615 Register scratch = scratch0();
3616
3617 // TODO(3095996): Get rid of this. For now, we need to make the
3618 // result register contain a valid pointer because it is already
3619 // contained in the register pointer map.
3620 __ mov(result, Operand(0));
3621
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003622 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003623 __ push(string);
3624 // Push the index as a smi. This is safe because of the checks in
3625 // DoStringCharCodeAt above.
3626 if (instr->index()->IsConstantOperand()) {
3627 int const_index = ToInteger32(LConstantOperand::cast(instr->index()));
3628 __ mov(scratch, Operand(Smi::FromInt(const_index)));
3629 __ push(scratch);
3630 } else {
3631 Register index = ToRegister(instr->index());
3632 __ SmiTag(index);
3633 __ push(index);
3634 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003635 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003636 if (FLAG_debug_code) {
3637 __ AbortIfNotSmi(r0);
3638 }
3639 __ SmiUntag(r0);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003640 __ StoreToSafepointRegisterSlot(r0, result);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003641}
3642
3643
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003644void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
3645 class DeferredStringCharFromCode: public LDeferredCode {
3646 public:
3647 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
3648 : LDeferredCode(codegen), instr_(instr) { }
3649 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
3650 private:
3651 LStringCharFromCode* instr_;
3652 };
3653
3654 DeferredStringCharFromCode* deferred =
3655 new DeferredStringCharFromCode(this, instr);
3656
3657 ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
3658 Register char_code = ToRegister(instr->char_code());
3659 Register result = ToRegister(instr->result());
3660 ASSERT(!char_code.is(result));
3661
3662 __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
3663 __ b(hi, deferred->entry());
3664 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
3665 __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
3666 __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize));
3667 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3668 __ cmp(result, ip);
3669 __ b(eq, deferred->entry());
3670 __ bind(deferred->exit());
3671}
3672
3673
3674void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
3675 Register char_code = ToRegister(instr->char_code());
3676 Register result = ToRegister(instr->result());
3677
3678 // TODO(3095996): Get rid of this. For now, we need to make the
3679 // result register contain a valid pointer because it is already
3680 // contained in the register pointer map.
3681 __ mov(result, Operand(0));
3682
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003683 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003684 __ SmiTag(char_code);
3685 __ push(char_code);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003686 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003687 __ StoreToSafepointRegisterSlot(r0, result);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00003688}
3689
3690
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003691void LCodeGen::DoStringLength(LStringLength* instr) {
3692 Register string = ToRegister(instr->InputAt(0));
3693 Register result = ToRegister(instr->result());
3694 __ ldr(result, FieldMemOperand(string, String::kLengthOffset));
3695}
3696
3697
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003698void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003699 LOperand* input = instr->InputAt(0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00003700 ASSERT(input->IsRegister() || input->IsStackSlot());
3701 LOperand* output = instr->result();
3702 ASSERT(output->IsDoubleRegister());
3703 SwVfpRegister single_scratch = double_scratch0().low();
3704 if (input->IsStackSlot()) {
3705 Register scratch = scratch0();
3706 __ ldr(scratch, ToMemOperand(input));
3707 __ vmov(single_scratch, scratch);
3708 } else {
3709 __ vmov(single_scratch, ToRegister(input));
3710 }
3711 __ vcvt_f64_s32(ToDoubleRegister(output), single_scratch);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003712}
3713
3714
3715void LCodeGen::DoNumberTagI(LNumberTagI* instr) {
3716 class DeferredNumberTagI: public LDeferredCode {
3717 public:
3718 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr)
3719 : LDeferredCode(codegen), instr_(instr) { }
3720 virtual void Generate() { codegen()->DoDeferredNumberTagI(instr_); }
3721 private:
3722 LNumberTagI* instr_;
3723 };
3724
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003725 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003726 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3727 Register reg = ToRegister(input);
3728
3729 DeferredNumberTagI* deferred = new DeferredNumberTagI(this, instr);
3730 __ SmiTag(reg, SetCC);
3731 __ b(vs, deferred->entry());
3732 __ bind(deferred->exit());
3733}
3734
3735
3736void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3737 Label slow;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003738 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003739 DoubleRegister dbl_scratch = d0;
3740 SwVfpRegister flt_scratch = s0;
3741
3742 // Preserve the value of all registers.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003743 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003744
3745 // There was overflow, so bits 30 and 31 of the original integer
3746 // disagree. Try to allocate a heap number in new space and store
3747 // the value in there. If that fails, call the runtime system.
3748 Label done;
3749 __ SmiUntag(reg);
3750 __ eor(reg, reg, Operand(0x80000000));
3751 __ vmov(flt_scratch, reg);
3752 __ vcvt_f64_s32(dbl_scratch, flt_scratch);
3753 if (FLAG_inline_new) {
3754 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3755 __ AllocateHeapNumber(r5, r3, r4, r6, &slow);
3756 if (!reg.is(r5)) __ mov(reg, r5);
3757 __ b(&done);
3758 }
3759
3760 // Slow case: Call the runtime system to do the number allocation.
3761 __ bind(&slow);
3762
3763 // TODO(3095996): Put a valid pointer value in the stack slot where the result
3764 // register is stored, as this register is in the pointer map, but contains an
3765 // integer value.
3766 __ mov(ip, Operand(0));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003767 __ StoreToSafepointRegisterSlot(ip, reg);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003768 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003769 if (!reg.is(r0)) __ mov(reg, r0);
3770
3771 // Done. Put the value in dbl_scratch into the value of the allocated heap
3772 // number.
3773 __ bind(&done);
3774 __ sub(ip, reg, Operand(kHeapObjectTag));
3775 __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003776 __ StoreToSafepointRegisterSlot(reg, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003777}
3778
3779
3780void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
3781 class DeferredNumberTagD: public LDeferredCode {
3782 public:
3783 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
3784 : LDeferredCode(codegen), instr_(instr) { }
3785 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
3786 private:
3787 LNumberTagD* instr_;
3788 };
3789
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003790 DoubleRegister input_reg = ToDoubleRegister(instr->InputAt(0));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003791 Register scratch = scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003792 Register reg = ToRegister(instr->result());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003793 Register temp1 = ToRegister(instr->TempAt(0));
3794 Register temp2 = ToRegister(instr->TempAt(1));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003795
3796 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr);
3797 if (FLAG_inline_new) {
3798 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003799 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003800 } else {
3801 __ jmp(deferred->entry());
3802 }
3803 __ bind(deferred->exit());
3804 __ sub(ip, reg, Operand(kHeapObjectTag));
3805 __ vstr(input_reg, ip, HeapNumber::kValueOffset);
3806}
3807
3808
3809void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
3810 // TODO(3095996): Get rid of this. For now, we need to make the
3811 // result register contain a valid pointer because it is already
3812 // contained in the register pointer map.
3813 Register reg = ToRegister(instr->result());
3814 __ mov(reg, Operand(0));
3815
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003816 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3817 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003818 __ StoreToSafepointRegisterSlot(r0, reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003819}
3820
3821
3822void LCodeGen::DoSmiTag(LSmiTag* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003823 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003824 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3825 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
3826 __ SmiTag(ToRegister(input));
3827}
3828
3829
3830void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003831 LOperand* input = instr->InputAt(0);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003832 ASSERT(input->IsRegister() && input->Equals(instr->result()));
3833 if (instr->needs_check()) {
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00003834 ASSERT(kHeapObjectTag == 1);
3835 // If the input is a HeapObject, SmiUntag will set the carry flag.
3836 __ SmiUntag(ToRegister(input), SetCC);
3837 DeoptimizeIf(cs, instr->environment());
3838 } else {
3839 __ SmiUntag(ToRegister(input));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003840 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003841}
3842
3843
3844void LCodeGen::EmitNumberUntagD(Register input_reg,
3845 DoubleRegister result_reg,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003846 bool deoptimize_on_undefined,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003847 LEnvironment* env) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003848 Register scratch = scratch0();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003849 SwVfpRegister flt_scratch = s0;
3850 ASSERT(!result_reg.is(d0));
3851
3852 Label load_smi, heap_number, done;
3853
3854 // Smi check.
3855 __ tst(input_reg, Operand(kSmiTagMask));
3856 __ b(eq, &load_smi);
3857
3858 // Heap number map check.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003859 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003860 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003861 __ cmp(scratch, Operand(ip));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003862 if (deoptimize_on_undefined) {
3863 DeoptimizeIf(ne, env);
3864 } else {
3865 Label heap_number;
3866 __ b(eq, &heap_number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003867
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003868 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3869 __ cmp(input_reg, Operand(ip));
3870 DeoptimizeIf(ne, env);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003871
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003872 // Convert undefined to NaN.
3873 __ LoadRoot(ip, Heap::kNanValueRootIndex);
3874 __ sub(ip, ip, Operand(kHeapObjectTag));
3875 __ vldr(result_reg, ip, HeapNumber::kValueOffset);
3876 __ jmp(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003877
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003878 __ bind(&heap_number);
3879 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003880 // Heap number to double register conversion.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003881 __ sub(ip, input_reg, Operand(kHeapObjectTag));
3882 __ vldr(result_reg, ip, HeapNumber::kValueOffset);
3883 __ jmp(&done);
3884
3885 // Smi to double register conversion
3886 __ bind(&load_smi);
3887 __ SmiUntag(input_reg); // Untag smi before converting to float.
3888 __ vmov(flt_scratch, input_reg);
3889 __ vcvt_f64_s32(result_reg, flt_scratch);
3890 __ SmiTag(input_reg); // Retag smi.
3891 __ bind(&done);
3892}
3893
3894
3895class DeferredTaggedToI: public LDeferredCode {
3896 public:
3897 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
3898 : LDeferredCode(codegen), instr_(instr) { }
3899 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); }
3900 private:
3901 LTaggedToI* instr_;
3902};
3903
3904
3905void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003906 Register input_reg = ToRegister(instr->InputAt(0));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003907 Register scratch1 = scratch0();
3908 Register scratch2 = ToRegister(instr->TempAt(0));
3909 DwVfpRegister double_scratch = double_scratch0();
3910 SwVfpRegister single_scratch = double_scratch.low();
3911
3912 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
3913 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
3914
3915 Label done;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003916
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00003917 // The input was optimistically untagged; revert it.
3918 // The carry flag is set when we reach this deferred code as we just executed
3919 // SmiUntag(heap_object, SetCC)
3920 ASSERT(kHeapObjectTag == 1);
3921 __ adc(input_reg, input_reg, Operand(input_reg));
3922
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003923 // Heap number map check.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003924 __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003925 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003926 __ cmp(scratch1, Operand(ip));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003927
3928 if (instr->truncating()) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003929 Register scratch3 = ToRegister(instr->TempAt(1));
3930 DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2));
3931 ASSERT(!scratch3.is(input_reg) &&
3932 !scratch3.is(scratch1) &&
3933 !scratch3.is(scratch2));
3934 // Performs a truncating conversion of a floating point number as used by
3935 // the JS bitwise operations.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003936 Label heap_number;
3937 __ b(eq, &heap_number);
3938 // Check for undefined. Undefined is converted to zero for truncating
3939 // conversions.
3940 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3941 __ cmp(input_reg, Operand(ip));
3942 DeoptimizeIf(ne, instr->environment());
3943 __ mov(input_reg, Operand(0));
3944 __ b(&done);
3945
3946 __ bind(&heap_number);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003947 __ sub(scratch1, input_reg, Operand(kHeapObjectTag));
3948 __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
3949
3950 __ EmitECMATruncate(input_reg,
3951 double_scratch2,
3952 single_scratch,
3953 scratch1,
3954 scratch2,
3955 scratch3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003956
3957 } else {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003958 CpuFeatures::Scope scope(VFP3);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003959 // Deoptimize if we don't have a heap number.
3960 DeoptimizeIf(ne, instr->environment());
3961
3962 __ sub(ip, input_reg, Operand(kHeapObjectTag));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003963 __ vldr(double_scratch, ip, HeapNumber::kValueOffset);
3964 __ EmitVFPTruncate(kRoundToZero,
3965 single_scratch,
3966 double_scratch,
3967 scratch1,
3968 scratch2,
3969 kCheckForInexactConversion);
3970 DeoptimizeIf(ne, instr->environment());
3971 // Load the result.
3972 __ vmov(input_reg, single_scratch);
3973
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003974 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003975 __ cmp(input_reg, Operand(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003976 __ b(ne, &done);
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003977 __ vmov(scratch1, double_scratch.high());
3978 __ tst(scratch1, Operand(HeapNumber::kSignMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003979 DeoptimizeIf(ne, instr->environment());
3980 }
3981 }
3982 __ bind(&done);
3983}
3984
3985
3986void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00003987 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003988 ASSERT(input->IsRegister());
3989 ASSERT(input->Equals(instr->result()));
3990
3991 Register input_reg = ToRegister(input);
3992
3993 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3994
ricow@chromium.orgdcebac02011-04-20 09:44:50 +00003995 // Optimistically untag the input.
3996 // If the input is a HeapObject, SmiUntag will set the carry flag.
3997 __ SmiUntag(input_reg, SetCC);
3998 // Branch to deferred code if the input was tagged.
3999 // The deferred code will take care of restoring the tag.
4000 __ b(cs, deferred->entry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004001 __ bind(deferred->exit());
4002}
4003
4004
4005void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004006 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004007 ASSERT(input->IsRegister());
4008 LOperand* result = instr->result();
4009 ASSERT(result->IsDoubleRegister());
4010
4011 Register input_reg = ToRegister(input);
4012 DoubleRegister result_reg = ToDoubleRegister(result);
4013
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004014 EmitNumberUntagD(input_reg, result_reg,
4015 instr->hydrogen()->deoptimize_on_undefined(),
4016 instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004017}
4018
4019
4020void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004021 Register result_reg = ToRegister(instr->result());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004022 Register scratch1 = scratch0();
4023 Register scratch2 = ToRegister(instr->TempAt(0));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004024 DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0));
4025 DwVfpRegister double_scratch = double_scratch0();
4026 SwVfpRegister single_scratch = double_scratch0().low();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004027
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004028 Label done;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004029
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004030 if (instr->truncating()) {
4031 Register scratch3 = ToRegister(instr->TempAt(1));
4032 __ EmitECMATruncate(result_reg,
4033 double_input,
4034 single_scratch,
4035 scratch1,
4036 scratch2,
4037 scratch3);
4038 } else {
4039 VFPRoundingMode rounding_mode = kRoundToMinusInf;
4040 __ EmitVFPTruncate(rounding_mode,
4041 single_scratch,
4042 double_input,
4043 scratch1,
4044 scratch2,
4045 kCheckForInexactConversion);
4046 // Deoptimize if we had a vfp invalid exception,
4047 // including inexact operation.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004048 DeoptimizeIf(ne, instr->environment());
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004049 // Retrieve the result.
4050 __ vmov(result_reg, single_scratch);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004051 }
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004052 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004053}
4054
4055
4056void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004057 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004058 __ tst(ToRegister(input), Operand(kSmiTagMask));
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00004059 DeoptimizeIf(ne, instr->environment());
4060}
4061
4062
4063void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
4064 LOperand* input = instr->InputAt(0);
4065 __ tst(ToRegister(input), Operand(kSmiTagMask));
4066 DeoptimizeIf(eq, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004067}
4068
4069
4070void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004071 Register input = ToRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004072 Register scratch = scratch0();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004073
4074 __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
4075 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004076
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004077 if (instr->hydrogen()->is_interval_check()) {
4078 InstanceType first;
4079 InstanceType last;
4080 instr->hydrogen()->GetCheckInterval(&first, &last);
4081
4082 __ cmp(scratch, Operand(first));
4083
4084 // If there is only one type in the interval check for equality.
4085 if (first == last) {
4086 DeoptimizeIf(ne, instr->environment());
4087 } else {
4088 DeoptimizeIf(lo, instr->environment());
4089 // Omit check for the last type.
4090 if (last != LAST_TYPE) {
4091 __ cmp(scratch, Operand(last));
4092 DeoptimizeIf(hi, instr->environment());
4093 }
4094 }
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004095 } else {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00004096 uint8_t mask;
4097 uint8_t tag;
4098 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
4099
4100 if (IsPowerOf2(mask)) {
4101 ASSERT(tag == 0 || IsPowerOf2(tag));
4102 __ tst(scratch, Operand(mask));
4103 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment());
4104 } else {
4105 __ and_(scratch, scratch, Operand(mask));
4106 __ cmp(scratch, Operand(tag));
4107 DeoptimizeIf(ne, instr->environment());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004108 }
4109 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004110}
4111
4112
4113void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004114 ASSERT(instr->InputAt(0)->IsRegister());
4115 Register reg = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004116 __ cmp(reg, Operand(instr->hydrogen()->target()));
4117 DeoptimizeIf(ne, instr->environment());
4118}
4119
4120
4121void LCodeGen::DoCheckMap(LCheckMap* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004122 Register scratch = scratch0();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004123 LOperand* input = instr->InputAt(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004124 ASSERT(input->IsRegister());
4125 Register reg = ToRegister(input);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004126 __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
4127 __ cmp(scratch, Operand(instr->hydrogen()->map()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004128 DeoptimizeIf(ne, instr->environment());
4129}
4130
4131
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004132void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
4133 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
4134 Register result_reg = ToRegister(instr->result());
4135 DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
4136 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
4137}
4138
4139
4140void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
4141 Register unclamped_reg = ToRegister(instr->unclamped());
4142 Register result_reg = ToRegister(instr->result());
4143 __ ClampUint8(result_reg, unclamped_reg);
4144}
4145
4146
4147void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
4148 Register scratch = scratch0();
4149 Register input_reg = ToRegister(instr->unclamped());
4150 Register result_reg = ToRegister(instr->result());
4151 DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
4152 Label is_smi, done, heap_number;
4153
4154 // Both smi and heap number cases are handled.
4155 __ JumpIfSmi(input_reg, &is_smi);
4156
4157 // Check for heap number
4158 __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
4159 __ cmp(scratch, Operand(factory()->heap_number_map()));
4160 __ b(eq, &heap_number);
4161
4162 // Check for undefined. Undefined is converted to zero for clamping
4163 // conversions.
4164 __ cmp(input_reg, Operand(factory()->undefined_value()));
4165 DeoptimizeIf(ne, instr->environment());
4166 __ movt(input_reg, 0);
4167 __ jmp(&done);
4168
4169 // Heap number
4170 __ bind(&heap_number);
4171 __ vldr(double_scratch0(), FieldMemOperand(input_reg,
4172 HeapNumber::kValueOffset));
4173 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
4174 __ jmp(&done);
4175
4176 // smi
4177 __ bind(&is_smi);
4178 __ SmiUntag(result_reg, input_reg);
4179 __ ClampUint8(result_reg, result_reg);
4180
4181 __ bind(&done);
4182}
4183
4184
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004185void LCodeGen::LoadHeapObject(Register result,
4186 Handle<HeapObject> object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 if (heap()->InNewSpace(*object)) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004188 Handle<JSGlobalPropertyCell> cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 factory()->NewJSGlobalPropertyCell(object);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004190 __ mov(result, Operand(cell));
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004191 __ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004192 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004193 __ mov(result, Operand(object));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004194 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004195}
4196
4197
4198void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004199 Register temp1 = ToRegister(instr->TempAt(0));
4200 Register temp2 = ToRegister(instr->TempAt(1));
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004201
4202 Handle<JSObject> holder = instr->holder();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004203 Handle<JSObject> current_prototype = instr->prototype();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004204
4205 // Load prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004206 LoadHeapObject(temp1, current_prototype);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004207
4208 // Check prototype maps up to the holder.
4209 while (!current_prototype.is_identical_to(holder)) {
4210 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
4211 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
4212 DeoptimizeIf(ne, instr->environment());
4213 current_prototype =
4214 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype()));
4215 // Load next prototype object.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004216 LoadHeapObject(temp1, current_prototype);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004217 }
4218
4219 // Check the holder map.
4220 __ ldr(temp2, FieldMemOperand(temp1, HeapObject::kMapOffset));
4221 __ cmp(temp2, Operand(Handle<Map>(current_prototype->map())));
4222 DeoptimizeIf(ne, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004223}
4224
4225
4226void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004227 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4228 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
4229 __ mov(r2, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
4230 __ mov(r1, Operand(instr->hydrogen()->constant_elements()));
4231 __ Push(r3, r2, r1);
4232
4233 // Pick the right runtime function or stub to call.
4234 int length = instr->hydrogen()->length();
4235 if (instr->hydrogen()->IsCopyOnWrite()) {
4236 ASSERT(instr->hydrogen()->depth() == 1);
4237 FastCloneShallowArrayStub::Mode mode =
4238 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
4239 FastCloneShallowArrayStub stub(mode, length);
4240 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4241 } else if (instr->hydrogen()->depth() > 1) {
4242 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
4243 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
4244 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
4245 } else {
4246 FastCloneShallowArrayStub::Mode mode =
4247 FastCloneShallowArrayStub::CLONE_ELEMENTS;
4248 FastCloneShallowArrayStub stub(mode, length);
4249 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4250 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004251}
4252
4253
4254void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004255 __ ldr(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4256 __ ldr(r4, FieldMemOperand(r4, JSFunction::kLiteralsOffset));
4257 __ mov(r3, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
4258 __ mov(r2, Operand(instr->hydrogen()->constant_properties()));
4259 __ mov(r1, Operand(Smi::FromInt(instr->hydrogen()->fast_elements() ? 1 : 0)));
4260 __ Push(r4, r3, r2, r1);
4261
4262 // Pick the right runtime function to call.
4263 if (instr->hydrogen()->depth() > 1) {
4264 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr);
4265 } else {
4266 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr);
4267 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004268}
4269
4270
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004271void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
4272 ASSERT(ToRegister(instr->InputAt(0)).is(r0));
4273 __ push(r0);
4274 CallRuntime(Runtime::kToFastProperties, 1, instr);
4275}
4276
4277
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004278void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004279 Label materialized;
4280 // Registers will be used as follows:
4281 // r3 = JS function.
4282 // r7 = literals array.
4283 // r1 = regexp literal.
4284 // r0 = regexp literal clone.
4285 // r2 and r4-r6 are used as temporaries.
4286 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4287 __ ldr(r7, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
4288 int literal_offset = FixedArray::kHeaderSize +
4289 instr->hydrogen()->literal_index() * kPointerSize;
4290 __ ldr(r1, FieldMemOperand(r7, literal_offset));
4291 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
4292 __ cmp(r1, ip);
4293 __ b(ne, &materialized);
4294
4295 // Create regexp literal using runtime function
4296 // Result will be in r0.
4297 __ mov(r6, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
4298 __ mov(r5, Operand(instr->hydrogen()->pattern()));
4299 __ mov(r4, Operand(instr->hydrogen()->flags()));
4300 __ Push(r7, r6, r5, r4);
4301 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
4302 __ mov(r1, r0);
4303
4304 __ bind(&materialized);
4305 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
4306 Label allocated, runtime_allocate;
4307
4308 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
4309 __ jmp(&allocated);
4310
4311 __ bind(&runtime_allocate);
4312 __ mov(r0, Operand(Smi::FromInt(size)));
4313 __ Push(r1, r0);
4314 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
4315 __ pop(r1);
4316
4317 __ bind(&allocated);
4318 // Copy the content into the newly allocated memory.
4319 // (Unroll copy loop once for better throughput).
4320 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
4321 __ ldr(r3, FieldMemOperand(r1, i));
4322 __ ldr(r2, FieldMemOperand(r1, i + kPointerSize));
4323 __ str(r3, FieldMemOperand(r0, i));
4324 __ str(r2, FieldMemOperand(r0, i + kPointerSize));
4325 }
4326 if ((size % (2 * kPointerSize)) != 0) {
4327 __ ldr(r3, FieldMemOperand(r1, size - kPointerSize));
4328 __ str(r3, FieldMemOperand(r0, size - kPointerSize));
4329 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004330}
4331
4332
4333void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004334 // Use the fast case closure allocation code that allocates in new
4335 // space for nested functions that don't need literals cloning.
4336 Handle<SharedFunctionInfo> shared_info = instr->shared_info();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004337 bool pretenure = instr->hydrogen()->pretenure();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004338 if (!pretenure && shared_info->num_literals() == 0) {
4339 FastNewClosureStub stub(
4340 shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004341 __ mov(r1, Operand(shared_info));
4342 __ push(r1);
4343 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4344 } else {
4345 __ mov(r2, Operand(shared_info));
4346 __ mov(r1, Operand(pretenure
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004347 ? factory()->true_value()
4348 : factory()->false_value()));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004349 __ Push(cp, r2, r1);
4350 CallRuntime(Runtime::kNewClosure, 3, instr);
4351 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004352}
4353
4354
4355void LCodeGen::DoTypeof(LTypeof* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004356 Register input = ToRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004357 __ push(input);
4358 CallRuntime(Runtime::kTypeof, 1, instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004359}
4360
4361
4362void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004363 Register input = ToRegister(instr->InputAt(0));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004364 Register result = ToRegister(instr->result());
4365 Label true_label;
4366 Label false_label;
4367 Label done;
4368
4369 Condition final_branch_condition = EmitTypeofIs(&true_label,
4370 &false_label,
4371 input,
4372 instr->type_literal());
4373 __ b(final_branch_condition, &true_label);
4374 __ bind(&false_label);
4375 __ LoadRoot(result, Heap::kFalseValueRootIndex);
4376 __ b(&done);
4377
4378 __ bind(&true_label);
4379 __ LoadRoot(result, Heap::kTrueValueRootIndex);
4380
4381 __ bind(&done);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004382}
4383
4384
4385void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00004386 Register input = ToRegister(instr->InputAt(0));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004387 int true_block = chunk_->LookupDestination(instr->true_block_id());
4388 int false_block = chunk_->LookupDestination(instr->false_block_id());
4389 Label* true_label = chunk_->GetAssemblyLabel(true_block);
4390 Label* false_label = chunk_->GetAssemblyLabel(false_block);
4391
4392 Condition final_branch_condition = EmitTypeofIs(true_label,
4393 false_label,
4394 input,
4395 instr->type_literal());
4396
4397 EmitBranch(true_block, false_block, final_branch_condition);
4398}
4399
4400
4401Condition LCodeGen::EmitTypeofIs(Label* true_label,
4402 Label* false_label,
4403 Register input,
4404 Handle<String> type_name) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00004405 Condition final_branch_condition = kNoCondition;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00004406 Register scratch = scratch0();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004407 if (type_name->Equals(heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004408 __ JumpIfSmi(input, true_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004409 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
4410 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
4411 __ cmp(input, Operand(ip));
4412 final_branch_condition = eq;
4413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 } else if (type_name->Equals(heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004415 __ JumpIfSmi(input, false_label);
4416 __ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE);
4417 __ b(ge, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004418 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
4419 __ tst(ip, Operand(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004420 final_branch_condition = eq;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 } else if (type_name->Equals(heap()->boolean_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004423 __ CompareRoot(input, Heap::kTrueValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004424 __ b(eq, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004425 __ CompareRoot(input, Heap::kFalseValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004426 final_branch_condition = eq;
4427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 } else if (type_name->Equals(heap()->undefined_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004429 __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004430 __ b(eq, true_label);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004431 __ JumpIfSmi(input, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004432 // Check for undetectable objects => true.
4433 __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
4434 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
4435 __ tst(ip, Operand(1 << Map::kIsUndetectable));
4436 final_branch_condition = ne;
4437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004438 } else if (type_name->Equals(heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004439 __ JumpIfSmi(input, false_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004440 __ CompareObjectType(input, input, scratch,
4441 FIRST_CALLABLE_SPEC_OBJECT_TYPE);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004442 final_branch_condition = ge;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004444 } else if (type_name->Equals(heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004445 __ JumpIfSmi(input, false_label);
4446 __ CompareRoot(input, Heap::kNullValueRootIndex);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004447 __ b(eq, true_label);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004448 __ CompareObjectType(input, input, scratch,
4449 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
4450 __ b(lt, false_label);
4451 __ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4452 __ b(gt, false_label);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004453 // Check for undetectable objects => false.
4454 __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
4455 __ tst(ip, Operand(1 << Map::kIsUndetectable));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004456 final_branch_condition = eq;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004457
4458 } else {
4459 final_branch_condition = ne;
4460 __ b(false_label);
4461 // A dead branch instruction will be generated after this point.
4462 }
4463
4464 return final_branch_condition;
4465}
4466
4467
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004468void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
4469 Register result = ToRegister(instr->result());
4470 Label true_label;
4471 Label false_label;
4472 Label done;
4473
4474 EmitIsConstructCall(result, scratch0());
4475 __ b(eq, &true_label);
4476
4477 __ LoadRoot(result, Heap::kFalseValueRootIndex);
4478 __ b(&done);
4479
4480
4481 __ bind(&true_label);
4482 __ LoadRoot(result, Heap::kTrueValueRootIndex);
4483
4484 __ bind(&done);
4485}
4486
4487
4488void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
4489 Register temp1 = ToRegister(instr->TempAt(0));
4490 int true_block = chunk_->LookupDestination(instr->true_block_id());
4491 int false_block = chunk_->LookupDestination(instr->false_block_id());
4492
4493 EmitIsConstructCall(temp1, scratch0());
4494 EmitBranch(true_block, false_block, eq);
4495}
4496
4497
4498void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) {
4499 ASSERT(!temp1.is(temp2));
4500 // Get the frame pointer for the calling frame.
4501 __ ldr(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
4502
4503 // Skip the arguments adaptor frame if it exists.
4504 Label check_frame_marker;
4505 __ ldr(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
4506 __ cmp(temp2, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
4507 __ b(ne, &check_frame_marker);
4508 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
4509
4510 // Check the marker in the calling frame.
4511 __ bind(&check_frame_marker);
4512 __ ldr(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
4513 __ cmp(temp1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
4514}
4515
4516
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004517void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
4518 // No code for lazy bailout instruction. Used to capture environment after a
4519 // call for populating the safepoint data with deoptimization data.
4520}
4521
4522
4523void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004524 DeoptimizeIf(al, instr->environment());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004525}
4526
4527
4528void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004529 Register object = ToRegister(instr->object());
4530 Register key = ToRegister(instr->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004531 Register strict = scratch0();
4532 __ mov(strict, Operand(Smi::FromInt(strict_mode_flag())));
4533 __ Push(object, key, strict);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004534 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4535 LPointerMap* pointers = instr->pointer_map();
4536 LEnvironment* env = instr->deoptimization_environment();
4537 RecordPosition(pointers->position());
4538 RegisterEnvironmentForDeoptimization(env);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004539 SafepointGenerator safepoint_generator(this,
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00004540 pointers,
4541 env->deoptimization_index());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004542 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004543}
4544
4545
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004546void LCodeGen::DoIn(LIn* instr) {
4547 Register obj = ToRegister(instr->object());
4548 Register key = ToRegister(instr->key());
4549 __ Push(key, obj);
4550 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
4551 LPointerMap* pointers = instr->pointer_map();
4552 LEnvironment* env = instr->deoptimization_environment();
4553 RecordPosition(pointers->position());
4554 RegisterEnvironmentForDeoptimization(env);
4555 SafepointGenerator safepoint_generator(this,
4556 pointers,
4557 env->deoptimization_index());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00004558 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004559}
4560
4561
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004562void LCodeGen::DoStackCheck(LStackCheck* instr) {
4563 // Perform stack overflow check.
4564 Label ok;
4565 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
4566 __ cmp(sp, Operand(ip));
4567 __ b(hs, &ok);
4568 StackCheckStub stub;
4569 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
4570 __ bind(&ok);
4571}
4572
4573
4574void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004575 // This is a pseudo-instruction that ensures that the environment here is
4576 // properly registered for deoptimization and records the assembler's PC
4577 // offset.
4578 LEnvironment* environment = instr->environment();
4579 environment->SetSpilledRegisters(instr->SpilledRegisterArray(),
4580 instr->SpilledDoubleRegisterArray());
4581
4582 // If the environment were already registered, we would have no way of
4583 // backpatching it with the spill slot operands.
4584 ASSERT(!environment->HasBeenRegistered());
4585 RegisterEnvironmentForDeoptimization(environment);
4586 ASSERT(osr_pc_offset_ == -1);
4587 osr_pc_offset_ = masm()->pc_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004588}
4589
4590
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004591
4592
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004593#undef __
4594
4595} } // namespace v8::internal