Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / compiler / arm64 / code-generator-arm64.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/code-generator.h"
6
7 #include "src/arm64/macro-assembler-arm64.h"
8 #include "src/compiler/code-generator-impl.h"
9 #include "src/compiler/gap-resolver.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/node-properties-inl.h"
12 #include "src/scopes.h"
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 #define __ masm()->
19
20
21 // Adds Arm64-specific methods to convert InstructionOperands.
22 class Arm64OperandConverter V8_FINAL : public InstructionOperandConverter {
23  public:
24   Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
25       : InstructionOperandConverter(gen, instr) {}
26
27   Register InputRegister32(int index) {
28     return ToRegister(instr_->InputAt(index)).W();
29   }
30
31   Register InputRegister64(int index) { return InputRegister(index); }
32
33   Operand InputImmediate(int index) {
34     return ToImmediate(instr_->InputAt(index));
35   }
36
37   Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
38
39   Operand InputOperand64(int index) { return InputOperand(index); }
40
41   Operand InputOperand32(int index) {
42     return ToOperand32(instr_->InputAt(index));
43   }
44
45   Register OutputRegister64() { return OutputRegister(); }
46
47   Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
48
49   MemOperand MemoryOperand(int* first_index) {
50     const int index = *first_index;
51     switch (AddressingModeField::decode(instr_->opcode())) {
52       case kMode_None:
53         break;
54       case kMode_MRI:
55         *first_index += 2;
56         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
57       case kMode_MRR:
58         *first_index += 2;
59         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
60                           SXTW);
61     }
62     UNREACHABLE();
63     return MemOperand(no_reg);
64   }
65
66   MemOperand MemoryOperand() {
67     int index = 0;
68     return MemoryOperand(&index);
69   }
70
71   Operand ToOperand(InstructionOperand* op) {
72     if (op->IsRegister()) {
73       return Operand(ToRegister(op));
74     }
75     return ToImmediate(op);
76   }
77
78   Operand ToOperand32(InstructionOperand* op) {
79     if (op->IsRegister()) {
80       return Operand(ToRegister(op).W());
81     }
82     return ToImmediate(op);
83   }
84
85   Operand ToImmediate(InstructionOperand* operand) {
86     Constant constant = ToConstant(operand);
87     switch (constant.type()) {
88       case Constant::kInt32:
89         return Operand(constant.ToInt32());
90       case Constant::kInt64:
91         return Operand(constant.ToInt64());
92       case Constant::kFloat64:
93         return Operand(
94             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
95       case Constant::kExternalReference:
96         return Operand(constant.ToExternalReference());
97       case Constant::kHeapObject:
98         return Operand(constant.ToHeapObject());
99     }
100     UNREACHABLE();
101     return Operand(-1);
102   }
103
104   MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const {
105     DCHECK(op != NULL);
106     DCHECK(!op->IsRegister());
107     DCHECK(!op->IsDoubleRegister());
108     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
109     // The linkage computes where all spill slots are located.
110     FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
111     return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
112                       offset.offset());
113   }
114 };
115
116
117 #define ASSEMBLE_SHIFT(asm_instr, width)                                       \
118   do {                                                                         \
119     if (instr->InputAt(1)->IsRegister()) {                                     \
120       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0),       \
121                    i.InputRegister##width(1));                                 \
122     } else {                                                                   \
123       int64_t imm = i.InputOperand##width(1).immediate().value();              \
124       __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0), imm); \
125     }                                                                          \
126   } while (0);
127
128
129 // Assembles an instruction after register allocation, producing machine code.
130 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
131   Arm64OperandConverter i(this, instr);
132   InstructionCode opcode = instr->opcode();
133   switch (ArchOpcodeField::decode(opcode)) {
134     case kArchJmp:
135       __ B(code_->GetLabel(i.InputBlock(0)));
136       break;
137     case kArchNop:
138       // don't emit code for nops.
139       break;
140     case kArchRet:
141       AssembleReturn();
142       break;
143     case kArchDeoptimize: {
144       int deoptimization_id = MiscField::decode(instr->opcode());
145       BuildTranslation(instr, deoptimization_id);
146
147       Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
148           isolate(), deoptimization_id, Deoptimizer::LAZY);
149       __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
150       break;
151     }
152     case kArm64Add:
153       __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
154       break;
155     case kArm64Add32:
156       if (FlagsModeField::decode(opcode) != kFlags_none) {
157         __ Adds(i.OutputRegister32(), i.InputRegister32(0),
158                 i.InputOperand32(1));
159       } else {
160         __ Add(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
161       }
162       break;
163     case kArm64And:
164       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
165       break;
166     case kArm64And32:
167       __ And(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
168       break;
169     case kArm64Mul:
170       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
171       break;
172     case kArm64Mul32:
173       __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
174       break;
175     case kArm64Idiv:
176       __ Sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
177       break;
178     case kArm64Idiv32:
179       __ Sdiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
180       break;
181     case kArm64Udiv:
182       __ Udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
183       break;
184     case kArm64Udiv32:
185       __ Udiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
186       break;
187     case kArm64Imod: {
188       UseScratchRegisterScope scope(masm());
189       Register temp = scope.AcquireX();
190       __ Sdiv(temp, i.InputRegister(0), i.InputRegister(1));
191       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
192       break;
193     }
194     case kArm64Imod32: {
195       UseScratchRegisterScope scope(masm());
196       Register temp = scope.AcquireW();
197       __ Sdiv(temp, i.InputRegister32(0), i.InputRegister32(1));
198       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
199               i.InputRegister32(0));
200       break;
201     }
202     case kArm64Umod: {
203       UseScratchRegisterScope scope(masm());
204       Register temp = scope.AcquireX();
205       __ Udiv(temp, i.InputRegister(0), i.InputRegister(1));
206       __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
207       break;
208     }
209     case kArm64Umod32: {
210       UseScratchRegisterScope scope(masm());
211       Register temp = scope.AcquireW();
212       __ Udiv(temp, i.InputRegister32(0), i.InputRegister32(1));
213       __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
214               i.InputRegister32(0));
215       break;
216     }
217     // TODO(dcarney): use mvn instr??
218     case kArm64Not:
219       __ Orn(i.OutputRegister(), xzr, i.InputOperand(0));
220       break;
221     case kArm64Not32:
222       __ Orn(i.OutputRegister32(), wzr, i.InputOperand32(0));
223       break;
224     case kArm64Neg:
225       __ Neg(i.OutputRegister(), i.InputOperand(0));
226       break;
227     case kArm64Neg32:
228       __ Neg(i.OutputRegister32(), i.InputOperand32(0));
229       break;
230     case kArm64Or:
231       __ Orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
232       break;
233     case kArm64Or32:
234       __ Orr(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
235       break;
236     case kArm64Xor:
237       __ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
238       break;
239     case kArm64Xor32:
240       __ Eor(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
241       break;
242     case kArm64Sub:
243       __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
244       break;
245     case kArm64Sub32:
246       if (FlagsModeField::decode(opcode) != kFlags_none) {
247         __ Subs(i.OutputRegister32(), i.InputRegister32(0),
248                 i.InputOperand32(1));
249       } else {
250         __ Sub(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
251       }
252       break;
253     case kArm64Shl:
254       ASSEMBLE_SHIFT(Lsl, 64);
255       break;
256     case kArm64Shl32:
257       ASSEMBLE_SHIFT(Lsl, 32);
258       break;
259     case kArm64Shr:
260       ASSEMBLE_SHIFT(Lsr, 64);
261       break;
262     case kArm64Shr32:
263       ASSEMBLE_SHIFT(Lsr, 32);
264       break;
265     case kArm64Sar:
266       ASSEMBLE_SHIFT(Asr, 64);
267       break;
268     case kArm64Sar32:
269       ASSEMBLE_SHIFT(Asr, 32);
270       break;
271     case kArm64CallCodeObject: {
272       if (instr->InputAt(0)->IsImmediate()) {
273         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
274         __ Call(code, RelocInfo::CODE_TARGET);
275         RecordSafepoint(instr->pointer_map(), Safepoint::kSimple, 0,
276                         Safepoint::kNoLazyDeopt);
277       } else {
278         Register reg = i.InputRegister(0);
279         int entry = Code::kHeaderSize - kHeapObjectTag;
280         __ Ldr(reg, MemOperand(reg, entry));
281         __ Call(reg);
282         RecordSafepoint(instr->pointer_map(), Safepoint::kSimple, 0,
283                         Safepoint::kNoLazyDeopt);
284       }
285       bool lazy_deopt = (MiscField::decode(instr->opcode()) == 1);
286       if (lazy_deopt) {
287         RecordLazyDeoptimizationEntry(instr);
288       }
289       // Meaningless instruction for ICs to overwrite.
290       AddNopForSmiCodeInlining();
291       break;
292     }
293     case kArm64CallJSFunction: {
294       Register func = i.InputRegister(0);
295
296       // TODO(jarin) The load of the context should be separated from the call.
297       __ Ldr(cp, FieldMemOperand(func, JSFunction::kContextOffset));
298       __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
299       __ Call(x10);
300
301       RecordSafepoint(instr->pointer_map(), Safepoint::kSimple, 0,
302                       Safepoint::kNoLazyDeopt);
303       RecordLazyDeoptimizationEntry(instr);
304       break;
305     }
306     case kArm64CallAddress: {
307       DirectCEntryStub stub(isolate());
308       stub.GenerateCall(masm(), i.InputRegister(0));
309       break;
310     }
311     case kArm64Claim: {
312       int words = MiscField::decode(instr->opcode());
313       __ Claim(words);
314       break;
315     }
316     case kArm64Poke: {
317       int slot = MiscField::decode(instr->opcode());
318       Operand operand(slot * kPointerSize);
319       __ Poke(i.InputRegister(0), operand);
320       break;
321     }
322     case kArm64PokePairZero: {
323       // TODO(dcarney): test slot offset and register order.
324       int slot = MiscField::decode(instr->opcode()) - 1;
325       __ PokePair(i.InputRegister(0), xzr, slot * kPointerSize);
326       break;
327     }
328     case kArm64PokePair: {
329       int slot = MiscField::decode(instr->opcode()) - 1;
330       __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize);
331       break;
332     }
333     case kArm64Drop: {
334       int words = MiscField::decode(instr->opcode());
335       __ Drop(words);
336       break;
337     }
338     case kArm64Cmp:
339       __ Cmp(i.InputRegister(0), i.InputOperand(1));
340       break;
341     case kArm64Cmp32:
342       __ Cmp(i.InputRegister32(0), i.InputOperand32(1));
343       break;
344     case kArm64Tst:
345       __ Tst(i.InputRegister(0), i.InputOperand(1));
346       break;
347     case kArm64Tst32:
348       __ Tst(i.InputRegister32(0), i.InputOperand32(1));
349       break;
350     case kArm64Float64Cmp:
351       __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
352       break;
353     case kArm64Float64Add:
354       __ Fadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
355               i.InputDoubleRegister(1));
356       break;
357     case kArm64Float64Sub:
358       __ Fsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
359               i.InputDoubleRegister(1));
360       break;
361     case kArm64Float64Mul:
362       __ Fmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
363               i.InputDoubleRegister(1));
364       break;
365     case kArm64Float64Div:
366       __ Fdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
367               i.InputDoubleRegister(1));
368       break;
369     case kArm64Float64Mod: {
370       // TODO(dcarney): implement directly. See note in lithium-codegen-arm64.cc
371       FrameScope scope(masm(), StackFrame::MANUAL);
372       DCHECK(d0.is(i.InputDoubleRegister(0)));
373       DCHECK(d1.is(i.InputDoubleRegister(1)));
374       DCHECK(d0.is(i.OutputDoubleRegister()));
375       // TODO(dcarney): make sure this saves all relevant registers.
376       __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
377                        0, 2);
378       break;
379     }
380     case kArm64Int32ToInt64:
381       __ Sxtw(i.OutputRegister(), i.InputRegister(0));
382       break;
383     case kArm64Int64ToInt32:
384       if (!i.OutputRegister().is(i.InputRegister(0))) {
385         __ Mov(i.OutputRegister(), i.InputRegister(0));
386       }
387       break;
388     case kArm64Float64ToInt32:
389       __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
390       break;
391     case kArm64Float64ToUint32:
392       __ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
393       break;
394     case kArm64Int32ToFloat64:
395       __ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
396       break;
397     case kArm64Uint32ToFloat64:
398       __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
399       break;
400     case kArm64LoadWord8:
401       __ Ldrb(i.OutputRegister(), i.MemoryOperand());
402       break;
403     case kArm64StoreWord8:
404       __ Strb(i.InputRegister(2), i.MemoryOperand());
405       break;
406     case kArm64LoadWord16:
407       __ Ldrh(i.OutputRegister(), i.MemoryOperand());
408       break;
409     case kArm64StoreWord16:
410       __ Strh(i.InputRegister(2), i.MemoryOperand());
411       break;
412     case kArm64LoadWord32:
413       __ Ldr(i.OutputRegister32(), i.MemoryOperand());
414       break;
415     case kArm64StoreWord32:
416       __ Str(i.InputRegister32(2), i.MemoryOperand());
417       break;
418     case kArm64LoadWord64:
419       __ Ldr(i.OutputRegister(), i.MemoryOperand());
420       break;
421     case kArm64StoreWord64:
422       __ Str(i.InputRegister(2), i.MemoryOperand());
423       break;
424     case kArm64Float64Load:
425       __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
426       break;
427     case kArm64Float64Store:
428       __ Str(i.InputDoubleRegister(2), i.MemoryOperand());
429       break;
430     case kArm64StoreWriteBarrier: {
431       Register object = i.InputRegister(0);
432       Register index = i.InputRegister(1);
433       Register value = i.InputRegister(2);
434       __ Add(index, object, Operand(index, SXTW));
435       __ Str(value, MemOperand(index));
436       SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
437                                 ? kSaveFPRegs
438                                 : kDontSaveFPRegs;
439       // TODO(dcarney): we shouldn't test write barriers from c calls.
440       LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
441       UseScratchRegisterScope scope(masm());
442       Register temp = no_reg;
443       if (csp.is(masm()->StackPointer())) {
444         temp = scope.AcquireX();
445         lr_status = kLRHasBeenSaved;
446         __ Push(lr, temp);  // Need to push a pair
447       }
448       __ RecordWrite(object, index, value, lr_status, mode);
449       if (csp.is(masm()->StackPointer())) {
450         __ Pop(temp, lr);
451       }
452       break;
453     }
454   }
455 }
456
457
458 // Assemble branches after this instruction.
459 void CodeGenerator::AssembleArchBranch(Instruction* instr,
460                                        FlagsCondition condition) {
461   Arm64OperandConverter i(this, instr);
462   Label done;
463
464   // Emit a branch. The true and false targets are always the last two inputs
465   // to the instruction.
466   BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
467   BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
468   bool fallthru = IsNextInAssemblyOrder(fblock);
469   Label* tlabel = code()->GetLabel(tblock);
470   Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
471   switch (condition) {
472     case kUnorderedEqual:
473       __ B(vs, flabel);
474     // Fall through.
475     case kEqual:
476       __ B(eq, tlabel);
477       break;
478     case kUnorderedNotEqual:
479       __ B(vs, tlabel);
480     // Fall through.
481     case kNotEqual:
482       __ B(ne, tlabel);
483       break;
484     case kSignedLessThan:
485       __ B(lt, tlabel);
486       break;
487     case kSignedGreaterThanOrEqual:
488       __ B(ge, tlabel);
489       break;
490     case kSignedLessThanOrEqual:
491       __ B(le, tlabel);
492       break;
493     case kSignedGreaterThan:
494       __ B(gt, tlabel);
495       break;
496     case kUnorderedLessThan:
497       __ B(vs, flabel);
498     // Fall through.
499     case kUnsignedLessThan:
500       __ B(lo, tlabel);
501       break;
502     case kUnorderedGreaterThanOrEqual:
503       __ B(vs, tlabel);
504     // Fall through.
505     case kUnsignedGreaterThanOrEqual:
506       __ B(hs, tlabel);
507       break;
508     case kUnorderedLessThanOrEqual:
509       __ B(vs, flabel);
510     // Fall through.
511     case kUnsignedLessThanOrEqual:
512       __ B(ls, tlabel);
513       break;
514     case kUnorderedGreaterThan:
515       __ B(vs, tlabel);
516     // Fall through.
517     case kUnsignedGreaterThan:
518       __ B(hi, tlabel);
519       break;
520     case kOverflow:
521       __ B(vs, tlabel);
522       break;
523     case kNotOverflow:
524       __ B(vc, tlabel);
525       break;
526   }
527   if (!fallthru) __ B(flabel);  // no fallthru to flabel.
528   __ Bind(&done);
529 }
530
531
532 // Assemble boolean materializations after this instruction.
533 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
534                                         FlagsCondition condition) {
535   Arm64OperandConverter i(this, instr);
536   Label done;
537
538   // Materialize a full 64-bit 1 or 0 value. The result register is always the
539   // last output of the instruction.
540   Label check;
541   DCHECK_NE(0, instr->OutputCount());
542   Register reg = i.OutputRegister(instr->OutputCount() - 1);
543   Condition cc = nv;
544   switch (condition) {
545     case kUnorderedEqual:
546       __ B(vc, &check);
547       __ Mov(reg, 0);
548       __ B(&done);
549     // Fall through.
550     case kEqual:
551       cc = eq;
552       break;
553     case kUnorderedNotEqual:
554       __ B(vc, &check);
555       __ Mov(reg, 1);
556       __ B(&done);
557     // Fall through.
558     case kNotEqual:
559       cc = ne;
560       break;
561     case kSignedLessThan:
562       cc = lt;
563       break;
564     case kSignedGreaterThanOrEqual:
565       cc = ge;
566       break;
567     case kSignedLessThanOrEqual:
568       cc = le;
569       break;
570     case kSignedGreaterThan:
571       cc = gt;
572       break;
573     case kUnorderedLessThan:
574       __ B(vc, &check);
575       __ Mov(reg, 0);
576       __ B(&done);
577     // Fall through.
578     case kUnsignedLessThan:
579       cc = lo;
580       break;
581     case kUnorderedGreaterThanOrEqual:
582       __ B(vc, &check);
583       __ Mov(reg, 1);
584       __ B(&done);
585     // Fall through.
586     case kUnsignedGreaterThanOrEqual:
587       cc = hs;
588       break;
589     case kUnorderedLessThanOrEqual:
590       __ B(vc, &check);
591       __ Mov(reg, 0);
592       __ B(&done);
593     // Fall through.
594     case kUnsignedLessThanOrEqual:
595       cc = ls;
596       break;
597     case kUnorderedGreaterThan:
598       __ B(vc, &check);
599       __ Mov(reg, 1);
600       __ B(&done);
601     // Fall through.
602     case kUnsignedGreaterThan:
603       cc = hi;
604       break;
605     case kOverflow:
606       cc = vs;
607       break;
608     case kNotOverflow:
609       cc = vc;
610       break;
611   }
612   __ bind(&check);
613   __ Cset(reg, cc);
614   __ Bind(&done);
615 }
616
617
618 // TODO(dcarney): increase stack slots in frame once before first use.
619 static int AlignedStackSlots(int stack_slots) {
620   if (stack_slots & 1) stack_slots++;
621   return stack_slots;
622 }
623
624
625 void CodeGenerator::AssemblePrologue() {
626   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
627   if (descriptor->kind() == CallDescriptor::kCallAddress) {
628     __ SetStackPointer(csp);
629     __ Push(lr, fp);
630     __ Mov(fp, csp);
631     // TODO(dcarney): correct callee saved registers.
632     __ PushCalleeSavedRegisters();
633     frame()->SetRegisterSaveAreaSize(20 * kPointerSize);
634   } else if (descriptor->IsJSFunctionCall()) {
635     CompilationInfo* info = linkage()->info();
636     __ SetStackPointer(jssp);
637     __ Prologue(info->IsCodePreAgingActive());
638     frame()->SetRegisterSaveAreaSize(
639         StandardFrameConstants::kFixedFrameSizeFromFp);
640
641     // Sloppy mode functions and builtins need to replace the receiver with the
642     // global proxy when called as functions (without an explicit receiver
643     // object).
644     // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
645     if (info->strict_mode() == SLOPPY && !info->is_native()) {
646       Label ok;
647       // +2 for return address and saved frame pointer.
648       int receiver_slot = info->scope()->num_parameters() + 2;
649       __ Ldr(x10, MemOperand(fp, receiver_slot * kXRegSize));
650       __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
651       __ Ldr(x10, GlobalObjectMemOperand());
652       __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
653       __ Str(x10, MemOperand(fp, receiver_slot * kXRegSize));
654       __ Bind(&ok);
655     }
656
657   } else {
658     __ SetStackPointer(jssp);
659     __ StubPrologue();
660     frame()->SetRegisterSaveAreaSize(
661         StandardFrameConstants::kFixedFrameSizeFromFp);
662   }
663   int stack_slots = frame()->GetSpillSlotCount();
664   if (stack_slots > 0) {
665     Register sp = __ StackPointer();
666     if (!sp.Is(csp)) {
667       __ Sub(sp, sp, stack_slots * kPointerSize);
668     }
669     __ Sub(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
670   }
671 }
672
673
674 void CodeGenerator::AssembleReturn() {
675   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
676   if (descriptor->kind() == CallDescriptor::kCallAddress) {
677     if (frame()->GetRegisterSaveAreaSize() > 0) {
678       // Remove this frame's spill slots first.
679       int stack_slots = frame()->GetSpillSlotCount();
680       if (stack_slots > 0) {
681         __ Add(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
682       }
683       // Restore registers.
684       // TODO(dcarney): correct callee saved registers.
685       __ PopCalleeSavedRegisters();
686     }
687     __ Mov(csp, fp);
688     __ Pop(fp, lr);
689     __ Ret();
690   } else {
691     __ Mov(jssp, fp);
692     __ Pop(fp, lr);
693     int pop_count =
694         descriptor->IsJSFunctionCall() ? descriptor->ParameterCount() : 0;
695     __ Drop(pop_count);
696     __ Ret();
697   }
698 }
699
700
701 void CodeGenerator::AssembleMove(InstructionOperand* source,
702                                  InstructionOperand* destination) {
703   Arm64OperandConverter g(this, NULL);
704   // Dispatch on the source and destination operand kinds.  Not all
705   // combinations are possible.
706   if (source->IsRegister()) {
707     DCHECK(destination->IsRegister() || destination->IsStackSlot());
708     Register src = g.ToRegister(source);
709     if (destination->IsRegister()) {
710       __ Mov(g.ToRegister(destination), src);
711     } else {
712       __ Str(src, g.ToMemOperand(destination, masm()));
713     }
714   } else if (source->IsStackSlot()) {
715     MemOperand src = g.ToMemOperand(source, masm());
716     DCHECK(destination->IsRegister() || destination->IsStackSlot());
717     if (destination->IsRegister()) {
718       __ Ldr(g.ToRegister(destination), src);
719     } else {
720       UseScratchRegisterScope scope(masm());
721       Register temp = scope.AcquireX();
722       __ Ldr(temp, src);
723       __ Str(temp, g.ToMemOperand(destination, masm()));
724     }
725   } else if (source->IsConstant()) {
726     ConstantOperand* constant_source = ConstantOperand::cast(source);
727     if (destination->IsRegister() || destination->IsStackSlot()) {
728       UseScratchRegisterScope scope(masm());
729       Register dst = destination->IsRegister() ? g.ToRegister(destination)
730                                                : scope.AcquireX();
731       Constant src = g.ToConstant(source);
732       if (src.type() == Constant::kHeapObject) {
733         __ LoadObject(dst, src.ToHeapObject());
734       } else {
735         __ Mov(dst, g.ToImmediate(source));
736       }
737       if (destination->IsStackSlot()) {
738         __ Str(dst, g.ToMemOperand(destination, masm()));
739       }
740     } else if (destination->IsDoubleRegister()) {
741       FPRegister result = g.ToDoubleRegister(destination);
742       __ Fmov(result, g.ToDouble(constant_source));
743     } else {
744       DCHECK(destination->IsDoubleStackSlot());
745       UseScratchRegisterScope scope(masm());
746       FPRegister temp = scope.AcquireD();
747       __ Fmov(temp, g.ToDouble(constant_source));
748       __ Str(temp, g.ToMemOperand(destination, masm()));
749     }
750   } else if (source->IsDoubleRegister()) {
751     FPRegister src = g.ToDoubleRegister(source);
752     if (destination->IsDoubleRegister()) {
753       FPRegister dst = g.ToDoubleRegister(destination);
754       __ Fmov(dst, src);
755     } else {
756       DCHECK(destination->IsDoubleStackSlot());
757       __ Str(src, g.ToMemOperand(destination, masm()));
758     }
759   } else if (source->IsDoubleStackSlot()) {
760     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
761     MemOperand src = g.ToMemOperand(source, masm());
762     if (destination->IsDoubleRegister()) {
763       __ Ldr(g.ToDoubleRegister(destination), src);
764     } else {
765       UseScratchRegisterScope scope(masm());
766       FPRegister temp = scope.AcquireD();
767       __ Ldr(temp, src);
768       __ Str(temp, g.ToMemOperand(destination, masm()));
769     }
770   } else {
771     UNREACHABLE();
772   }
773 }
774
775
776 void CodeGenerator::AssembleSwap(InstructionOperand* source,
777                                  InstructionOperand* destination) {
778   Arm64OperandConverter g(this, NULL);
779   // Dispatch on the source and destination operand kinds.  Not all
780   // combinations are possible.
781   if (source->IsRegister()) {
782     // Register-register.
783     UseScratchRegisterScope scope(masm());
784     Register temp = scope.AcquireX();
785     Register src = g.ToRegister(source);
786     if (destination->IsRegister()) {
787       Register dst = g.ToRegister(destination);
788       __ Mov(temp, src);
789       __ Mov(src, dst);
790       __ Mov(dst, temp);
791     } else {
792       DCHECK(destination->IsStackSlot());
793       MemOperand dst = g.ToMemOperand(destination, masm());
794       __ Mov(temp, src);
795       __ Ldr(src, dst);
796       __ Str(temp, dst);
797     }
798   } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
799     UseScratchRegisterScope scope(masm());
800     CPURegister temp_0 = scope.AcquireX();
801     CPURegister temp_1 = scope.AcquireX();
802     MemOperand src = g.ToMemOperand(source, masm());
803     MemOperand dst = g.ToMemOperand(destination, masm());
804     __ Ldr(temp_0, src);
805     __ Ldr(temp_1, dst);
806     __ Str(temp_0, dst);
807     __ Str(temp_1, src);
808   } else if (source->IsDoubleRegister()) {
809     UseScratchRegisterScope scope(masm());
810     FPRegister temp = scope.AcquireD();
811     FPRegister src = g.ToDoubleRegister(source);
812     if (destination->IsDoubleRegister()) {
813       FPRegister dst = g.ToDoubleRegister(destination);
814       __ Fmov(temp, src);
815       __ Fmov(src, dst);
816       __ Fmov(src, temp);
817     } else {
818       DCHECK(destination->IsDoubleStackSlot());
819       MemOperand dst = g.ToMemOperand(destination, masm());
820       __ Fmov(temp, src);
821       __ Ldr(src, dst);
822       __ Str(temp, dst);
823     }
824   } else {
825     // No other combinations are possible.
826     UNREACHABLE();
827   }
828 }
829
830
831 void CodeGenerator::AddNopForSmiCodeInlining() { __ movz(xzr, 0); }
832
833 #undef __
834
835 #if DEBUG
836
837 // Checks whether the code between start_pc and end_pc is a no-op.
838 bool CodeGenerator::IsNopForSmiCodeInlining(Handle<Code> code, int start_pc,
839                                             int end_pc) {
840   if (start_pc + 4 != end_pc) {
841     return false;
842   }
843   Address instr_address = code->instruction_start() + start_pc;
844
845   v8::internal::Instruction* instr =
846       reinterpret_cast<v8::internal::Instruction*>(instr_address);
847   return instr->IsMovz() && instr->Rd() == xzr.code() && instr->SixtyFourBits();
848 }
849
850 #endif  // DEBUG
851
852 }  // namespace compiler
853 }  // namespace internal
854 }  // namespace v8