Upgrade to 3.29

Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.

Bug: 17370214

Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc
new file mode 100644
index 0000000..31c53d3
--- /dev/null
+++ b/src/compiler/arm64/code-generator-arm64.cc
@@ -0,0 +1,879 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/code-generator.h"
+
+#include "src/arm64/macro-assembler-arm64.h"
+#include "src/compiler/code-generator-impl.h"
+#include "src/compiler/gap-resolver.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define __ masm()->
+
+
+// Adds Arm64-specific methods to convert InstructionOperands.
+class Arm64OperandConverter FINAL : public InstructionOperandConverter {
+ public:
+  Arm64OperandConverter(CodeGenerator* gen, Instruction* instr)
+      : InstructionOperandConverter(gen, instr) {}
+
+  Register InputRegister32(int index) {
+    return ToRegister(instr_->InputAt(index)).W();
+  }
+
+  Register InputRegister64(int index) { return InputRegister(index); }
+
+  Operand InputImmediate(int index) {
+    return ToImmediate(instr_->InputAt(index));
+  }
+
+  Operand InputOperand(int index) { return ToOperand(instr_->InputAt(index)); }
+
+  Operand InputOperand64(int index) { return InputOperand(index); }
+
+  Operand InputOperand32(int index) {
+    return ToOperand32(instr_->InputAt(index));
+  }
+
+  Register OutputRegister64() { return OutputRegister(); }
+
+  Register OutputRegister32() { return ToRegister(instr_->Output()).W(); }
+
+  MemOperand MemoryOperand(int* first_index) {
+    const int index = *first_index;
+    switch (AddressingModeField::decode(instr_->opcode())) {
+      case kMode_None:
+        break;
+      case kMode_MRI:
+        *first_index += 2;
+        return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
+      case kMode_MRR:
+        *first_index += 2;
+        return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
+                          SXTW);
+    }
+    UNREACHABLE();
+    return MemOperand(no_reg);
+  }
+
+  MemOperand MemoryOperand() {
+    int index = 0;
+    return MemoryOperand(&index);
+  }
+
+  Operand ToOperand(InstructionOperand* op) {
+    if (op->IsRegister()) {
+      return Operand(ToRegister(op));
+    }
+    return ToImmediate(op);
+  }
+
+  Operand ToOperand32(InstructionOperand* op) {
+    if (op->IsRegister()) {
+      return Operand(ToRegister(op).W());
+    }
+    return ToImmediate(op);
+  }
+
+  Operand ToImmediate(InstructionOperand* operand) {
+    Constant constant = ToConstant(operand);
+    switch (constant.type()) {
+      case Constant::kInt32:
+        return Operand(constant.ToInt32());
+      case Constant::kInt64:
+        return Operand(constant.ToInt64());
+      case Constant::kFloat64:
+        return Operand(
+            isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
+      case Constant::kExternalReference:
+        return Operand(constant.ToExternalReference());
+      case Constant::kHeapObject:
+        return Operand(constant.ToHeapObject());
+    }
+    UNREACHABLE();
+    return Operand(-1);
+  }
+
+  MemOperand ToMemOperand(InstructionOperand* op, MacroAssembler* masm) const {
+    DCHECK(op != NULL);
+    DCHECK(!op->IsRegister());
+    DCHECK(!op->IsDoubleRegister());
+    DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
+    // The linkage computes where all spill slots are located.
+    FrameOffset offset = linkage()->GetFrameOffset(op->index(), frame(), 0);
+    return MemOperand(offset.from_stack_pointer() ? masm->StackPointer() : fp,
+                      offset.offset());
+  }
+};
+
+
+#define ASSEMBLE_SHIFT(asm_instr, width)                                       \
+  do {                                                                         \
+    if (instr->InputAt(1)->IsRegister()) {                                     \
+      __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0),       \
+                   i.InputRegister##width(1));                                 \
+    } else {                                                                   \
+      int64_t imm = i.InputOperand##width(1).immediate().value();              \
+      __ asm_instr(i.OutputRegister##width(), i.InputRegister##width(0), imm); \
+    }                                                                          \
+  } while (0);
+
+
+// Assembles an instruction after register allocation, producing machine code.
+void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
+  Arm64OperandConverter i(this, instr);
+  InstructionCode opcode = instr->opcode();
+  switch (ArchOpcodeField::decode(opcode)) {
+    case kArchCallCodeObject: {
+      EnsureSpaceForLazyDeopt();
+      if (instr->InputAt(0)->IsImmediate()) {
+        __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
+                RelocInfo::CODE_TARGET);
+      } else {
+        Register target = i.InputRegister(0);
+        __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
+        __ Call(target);
+      }
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchCallJSFunction: {
+      EnsureSpaceForLazyDeopt();
+      Register func = i.InputRegister(0);
+      if (FLAG_debug_code) {
+        // Check the function's context matches the context argument.
+        UseScratchRegisterScope scope(masm());
+        Register temp = scope.AcquireX();
+        __ Ldr(temp, FieldMemOperand(func, JSFunction::kContextOffset));
+        __ cmp(cp, temp);
+        __ Assert(eq, kWrongFunctionContext);
+      }
+      __ Ldr(x10, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
+      __ Call(x10);
+      AddSafepointAndDeopt(instr);
+      break;
+    }
+    case kArchJmp:
+      __ B(code_->GetLabel(i.InputBlock(0)));
+      break;
+    case kArchNop:
+      // don't emit code for nops.
+      break;
+    case kArchRet:
+      AssembleReturn();
+      break;
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Add:
+      __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Add32:
+      if (FlagsModeField::decode(opcode) != kFlags_none) {
+        __ Adds(i.OutputRegister32(), i.InputRegister32(0),
+                i.InputOperand32(1));
+      } else {
+        __ Add(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      }
+      break;
+    case kArm64And:
+      __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64And32:
+      __ And(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Mul:
+      __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      break;
+    case kArm64Mul32:
+      __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
+    case kArm64Idiv:
+      __ Sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      break;
+    case kArm64Idiv32:
+      __ Sdiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
+    case kArm64Udiv:
+      __ Udiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      break;
+    case kArm64Udiv32:
+      __ Udiv(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
+    case kArm64Imod: {
+      UseScratchRegisterScope scope(masm());
+      Register temp = scope.AcquireX();
+      __ Sdiv(temp, i.InputRegister(0), i.InputRegister(1));
+      __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
+      break;
+    }
+    case kArm64Imod32: {
+      UseScratchRegisterScope scope(masm());
+      Register temp = scope.AcquireW();
+      __ Sdiv(temp, i.InputRegister32(0), i.InputRegister32(1));
+      __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
+              i.InputRegister32(0));
+      break;
+    }
+    case kArm64Umod: {
+      UseScratchRegisterScope scope(masm());
+      Register temp = scope.AcquireX();
+      __ Udiv(temp, i.InputRegister(0), i.InputRegister(1));
+      __ Msub(i.OutputRegister(), temp, i.InputRegister(1), i.InputRegister(0));
+      break;
+    }
+    case kArm64Umod32: {
+      UseScratchRegisterScope scope(masm());
+      Register temp = scope.AcquireW();
+      __ Udiv(temp, i.InputRegister32(0), i.InputRegister32(1));
+      __ Msub(i.OutputRegister32(), temp, i.InputRegister32(1),
+              i.InputRegister32(0));
+      break;
+    }
+    // TODO(dcarney): use mvn instr??
+    case kArm64Not:
+      __ Orn(i.OutputRegister(), xzr, i.InputOperand(0));
+      break;
+    case kArm64Not32:
+      __ Orn(i.OutputRegister32(), wzr, i.InputOperand32(0));
+      break;
+    case kArm64Neg:
+      __ Neg(i.OutputRegister(), i.InputOperand(0));
+      break;
+    case kArm64Neg32:
+      __ Neg(i.OutputRegister32(), i.InputOperand32(0));
+      break;
+    case kArm64Or:
+      __ Orr(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Or32:
+      __ Orr(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Xor:
+      __ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Xor32:
+      __ Eor(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Sub:
+      __ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Sub32:
+      if (FlagsModeField::decode(opcode) != kFlags_none) {
+        __ Subs(i.OutputRegister32(), i.InputRegister32(0),
+                i.InputOperand32(1));
+      } else {
+        __ Sub(i.OutputRegister32(), i.InputRegister32(0), i.InputOperand32(1));
+      }
+      break;
+    case kArm64Shl:
+      ASSEMBLE_SHIFT(Lsl, 64);
+      break;
+    case kArm64Shl32:
+      ASSEMBLE_SHIFT(Lsl, 32);
+      break;
+    case kArm64Shr:
+      ASSEMBLE_SHIFT(Lsr, 64);
+      break;
+    case kArm64Shr32:
+      ASSEMBLE_SHIFT(Lsr, 32);
+      break;
+    case kArm64Sar:
+      ASSEMBLE_SHIFT(Asr, 64);
+      break;
+    case kArm64Sar32:
+      ASSEMBLE_SHIFT(Asr, 32);
+      break;
+    case kArm64Ror:
+      ASSEMBLE_SHIFT(Ror, 64);
+      break;
+    case kArm64Ror32:
+      ASSEMBLE_SHIFT(Ror, 32);
+      break;
+    case kArm64Mov32:
+      __ Mov(i.OutputRegister32(), i.InputRegister32(0));
+      break;
+    case kArm64Sxtw:
+      __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
+      break;
+    case kArm64Claim: {
+      int words = MiscField::decode(instr->opcode());
+      __ Claim(words);
+      break;
+    }
+    case kArm64Poke: {
+      int slot = MiscField::decode(instr->opcode());
+      Operand operand(slot * kPointerSize);
+      __ Poke(i.InputRegister(0), operand);
+      break;
+    }
+    case kArm64PokePairZero: {
+      // TODO(dcarney): test slot offset and register order.
+      int slot = MiscField::decode(instr->opcode()) - 1;
+      __ PokePair(i.InputRegister(0), xzr, slot * kPointerSize);
+      break;
+    }
+    case kArm64PokePair: {
+      int slot = MiscField::decode(instr->opcode()) - 1;
+      __ PokePair(i.InputRegister(1), i.InputRegister(0), slot * kPointerSize);
+      break;
+    }
+    case kArm64Cmp:
+      __ Cmp(i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Cmp32:
+      __ Cmp(i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Cmn:
+      __ Cmn(i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Cmn32:
+      __ Cmn(i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Tst:
+      __ Tst(i.InputRegister(0), i.InputOperand(1));
+      break;
+    case kArm64Tst32:
+      __ Tst(i.InputRegister32(0), i.InputOperand32(1));
+      break;
+    case kArm64Float64Cmp:
+      __ Fcmp(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Add:
+      __ Fadd(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Sub:
+      __ Fsub(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Mul:
+      __ Fmul(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Div:
+      __ Fdiv(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
+              i.InputDoubleRegister(1));
+      break;
+    case kArm64Float64Mod: {
+      // TODO(dcarney): implement directly. See note in lithium-codegen-arm64.cc
+      FrameScope scope(masm(), StackFrame::MANUAL);
+      DCHECK(d0.is(i.InputDoubleRegister(0)));
+      DCHECK(d1.is(i.InputDoubleRegister(1)));
+      DCHECK(d0.is(i.OutputDoubleRegister()));
+      // TODO(dcarney): make sure this saves all relevant registers.
+      __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()),
+                       0, 2);
+      break;
+    }
+    case kArm64Float64Sqrt:
+      __ Fsqrt(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Float64ToInt32:
+      __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Float64ToUint32:
+      __ Fcvtzu(i.OutputRegister32(), i.InputDoubleRegister(0));
+      break;
+    case kArm64Int32ToFloat64:
+      __ Scvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
+      break;
+    case kArm64Uint32ToFloat64:
+      __ Ucvtf(i.OutputDoubleRegister(), i.InputRegister32(0));
+      break;
+    case kArm64Ldrb:
+      __ Ldrb(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kArm64Ldrsb:
+      __ Ldrsb(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kArm64Strb:
+      __ Strb(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kArm64Ldrh:
+      __ Ldrh(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kArm64Ldrsh:
+      __ Ldrsh(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kArm64Strh:
+      __ Strh(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kArm64LdrW:
+      __ Ldr(i.OutputRegister32(), i.MemoryOperand());
+      break;
+    case kArm64StrW:
+      __ Str(i.InputRegister32(2), i.MemoryOperand());
+      break;
+    case kArm64Ldr:
+      __ Ldr(i.OutputRegister(), i.MemoryOperand());
+      break;
+    case kArm64Str:
+      __ Str(i.InputRegister(2), i.MemoryOperand());
+      break;
+    case kArm64LdrS: {
+      UseScratchRegisterScope scope(masm());
+      FPRegister scratch = scope.AcquireS();
+      __ Ldr(scratch, i.MemoryOperand());
+      __ Fcvt(i.OutputDoubleRegister(), scratch);
+      break;
+    }
+    case kArm64StrS: {
+      UseScratchRegisterScope scope(masm());
+      FPRegister scratch = scope.AcquireS();
+      __ Fcvt(scratch, i.InputDoubleRegister(2));
+      __ Str(scratch, i.MemoryOperand());
+      break;
+    }
+    case kArm64LdrD:
+      __ Ldr(i.OutputDoubleRegister(), i.MemoryOperand());
+      break;
+    case kArm64StrD:
+      __ Str(i.InputDoubleRegister(2), i.MemoryOperand());
+      break;
+    case kArm64StoreWriteBarrier: {
+      Register object = i.InputRegister(0);
+      Register index = i.InputRegister(1);
+      Register value = i.InputRegister(2);
+      __ Add(index, object, Operand(index, SXTW));
+      __ Str(value, MemOperand(index));
+      SaveFPRegsMode mode = code_->frame()->DidAllocateDoubleRegisters()
+                                ? kSaveFPRegs
+                                : kDontSaveFPRegs;
+      // TODO(dcarney): we shouldn't test write barriers from c calls.
+      LinkRegisterStatus lr_status = kLRHasNotBeenSaved;
+      UseScratchRegisterScope scope(masm());
+      Register temp = no_reg;
+      if (csp.is(masm()->StackPointer())) {
+        temp = scope.AcquireX();
+        lr_status = kLRHasBeenSaved;
+        __ Push(lr, temp);  // Need to push a pair
+      }
+      __ RecordWrite(object, index, value, lr_status, mode);
+      if (csp.is(masm()->StackPointer())) {
+        __ Pop(temp, lr);
+      }
+      break;
+    }
+  }
+}
+
+
+// Assemble branches after this instruction.
+void CodeGenerator::AssembleArchBranch(Instruction* instr,
+                                       FlagsCondition condition) {
+  Arm64OperandConverter i(this, instr);
+  Label done;
+
+  // Emit a branch. The true and false targets are always the last two inputs
+  // to the instruction.
+  BasicBlock* tblock = i.InputBlock(instr->InputCount() - 2);
+  BasicBlock* fblock = i.InputBlock(instr->InputCount() - 1);
+  bool fallthru = IsNextInAssemblyOrder(fblock);
+  Label* tlabel = code()->GetLabel(tblock);
+  Label* flabel = fallthru ? &done : code()->GetLabel(fblock);
+  switch (condition) {
+    case kUnorderedEqual:
+      __ B(vs, flabel);
+    // Fall through.
+    case kEqual:
+      __ B(eq, tlabel);
+      break;
+    case kUnorderedNotEqual:
+      __ B(vs, tlabel);
+    // Fall through.
+    case kNotEqual:
+      __ B(ne, tlabel);
+      break;
+    case kSignedLessThan:
+      __ B(lt, tlabel);
+      break;
+    case kSignedGreaterThanOrEqual:
+      __ B(ge, tlabel);
+      break;
+    case kSignedLessThanOrEqual:
+      __ B(le, tlabel);
+      break;
+    case kSignedGreaterThan:
+      __ B(gt, tlabel);
+      break;
+    case kUnorderedLessThan:
+      __ B(vs, flabel);
+    // Fall through.
+    case kUnsignedLessThan:
+      __ B(lo, tlabel);
+      break;
+    case kUnorderedGreaterThanOrEqual:
+      __ B(vs, tlabel);
+    // Fall through.
+    case kUnsignedGreaterThanOrEqual:
+      __ B(hs, tlabel);
+      break;
+    case kUnorderedLessThanOrEqual:
+      __ B(vs, flabel);
+    // Fall through.
+    case kUnsignedLessThanOrEqual:
+      __ B(ls, tlabel);
+      break;
+    case kUnorderedGreaterThan:
+      __ B(vs, tlabel);
+    // Fall through.
+    case kUnsignedGreaterThan:
+      __ B(hi, tlabel);
+      break;
+    case kOverflow:
+      __ B(vs, tlabel);
+      break;
+    case kNotOverflow:
+      __ B(vc, tlabel);
+      break;
+  }
+  if (!fallthru) __ B(flabel);  // no fallthru to flabel.
+  __ Bind(&done);
+}
+
+
+// Assemble boolean materializations after this instruction.
+void CodeGenerator::AssembleArchBoolean(Instruction* instr,
+                                        FlagsCondition condition) {
+  Arm64OperandConverter i(this, instr);
+  Label done;
+
+  // Materialize a full 64-bit 1 or 0 value. The result register is always the
+  // last output of the instruction.
+  Label check;
+  DCHECK_NE(0, instr->OutputCount());
+  Register reg = i.OutputRegister(instr->OutputCount() - 1);
+  Condition cc = nv;
+  switch (condition) {
+    case kUnorderedEqual:
+      __ B(vc, &check);
+      __ Mov(reg, 0);
+      __ B(&done);
+    // Fall through.
+    case kEqual:
+      cc = eq;
+      break;
+    case kUnorderedNotEqual:
+      __ B(vc, &check);
+      __ Mov(reg, 1);
+      __ B(&done);
+    // Fall through.
+    case kNotEqual:
+      cc = ne;
+      break;
+    case kSignedLessThan:
+      cc = lt;
+      break;
+    case kSignedGreaterThanOrEqual:
+      cc = ge;
+      break;
+    case kSignedLessThanOrEqual:
+      cc = le;
+      break;
+    case kSignedGreaterThan:
+      cc = gt;
+      break;
+    case kUnorderedLessThan:
+      __ B(vc, &check);
+      __ Mov(reg, 0);
+      __ B(&done);
+    // Fall through.
+    case kUnsignedLessThan:
+      cc = lo;
+      break;
+    case kUnorderedGreaterThanOrEqual:
+      __ B(vc, &check);
+      __ Mov(reg, 1);
+      __ B(&done);
+    // Fall through.
+    case kUnsignedGreaterThanOrEqual:
+      cc = hs;
+      break;
+    case kUnorderedLessThanOrEqual:
+      __ B(vc, &check);
+      __ Mov(reg, 0);
+      __ B(&done);
+    // Fall through.
+    case kUnsignedLessThanOrEqual:
+      cc = ls;
+      break;
+    case kUnorderedGreaterThan:
+      __ B(vc, &check);
+      __ Mov(reg, 1);
+      __ B(&done);
+    // Fall through.
+    case kUnsignedGreaterThan:
+      cc = hi;
+      break;
+    case kOverflow:
+      cc = vs;
+      break;
+    case kNotOverflow:
+      cc = vc;
+      break;
+  }
+  __ bind(&check);
+  __ Cset(reg, cc);
+  __ Bind(&done);
+}
+
+
+void CodeGenerator::AssembleDeoptimizerCall(int deoptimization_id) {
+  Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
+      isolate(), deoptimization_id, Deoptimizer::LAZY);
+  __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
+}
+
+
+// TODO(dcarney): increase stack slots in frame once before first use.
+static int AlignedStackSlots(int stack_slots) {
+  if (stack_slots & 1) stack_slots++;
+  return stack_slots;
+}
+
+
+void CodeGenerator::AssemblePrologue() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    __ SetStackPointer(csp);
+    __ Push(lr, fp);
+    __ Mov(fp, csp);
+    // TODO(dcarney): correct callee saved registers.
+    __ PushCalleeSavedRegisters();
+    frame()->SetRegisterSaveAreaSize(20 * kPointerSize);
+  } else if (descriptor->IsJSFunctionCall()) {
+    CompilationInfo* info = linkage()->info();
+    __ SetStackPointer(jssp);
+    __ Prologue(info->IsCodePreAgingActive());
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+
+    // Sloppy mode functions and builtins need to replace the receiver with the
+    // global proxy when called as functions (without an explicit receiver
+    // object).
+    // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
+    if (info->strict_mode() == SLOPPY && !info->is_native()) {
+      Label ok;
+      // +2 for return address and saved frame pointer.
+      int receiver_slot = info->scope()->num_parameters() + 2;
+      __ Ldr(x10, MemOperand(fp, receiver_slot * kXRegSize));
+      __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
+      __ Ldr(x10, GlobalObjectMemOperand());
+      __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
+      __ Str(x10, MemOperand(fp, receiver_slot * kXRegSize));
+      __ Bind(&ok);
+    }
+
+  } else {
+    __ SetStackPointer(jssp);
+    __ StubPrologue();
+    frame()->SetRegisterSaveAreaSize(
+        StandardFrameConstants::kFixedFrameSizeFromFp);
+  }
+  int stack_slots = frame()->GetSpillSlotCount();
+  if (stack_slots > 0) {
+    Register sp = __ StackPointer();
+    if (!sp.Is(csp)) {
+      __ Sub(sp, sp, stack_slots * kPointerSize);
+    }
+    __ Sub(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
+  }
+}
+
+
+void CodeGenerator::AssembleReturn() {
+  CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
+  if (descriptor->kind() == CallDescriptor::kCallAddress) {
+    if (frame()->GetRegisterSaveAreaSize() > 0) {
+      // Remove this frame's spill slots first.
+      int stack_slots = frame()->GetSpillSlotCount();
+      if (stack_slots > 0) {
+        __ Add(csp, csp, AlignedStackSlots(stack_slots) * kPointerSize);
+      }
+      // Restore registers.
+      // TODO(dcarney): correct callee saved registers.
+      __ PopCalleeSavedRegisters();
+    }
+    __ Mov(csp, fp);
+    __ Pop(fp, lr);
+    __ Ret();
+  } else {
+    __ Mov(jssp, fp);
+    __ Pop(fp, lr);
+    int pop_count = descriptor->IsJSFunctionCall()
+                        ? static_cast<int>(descriptor->JSParameterCount())
+                        : 0;
+    __ Drop(pop_count);
+    __ Ret();
+  }
+}
+
+
+void CodeGenerator::AssembleMove(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  Arm64OperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      __ Mov(g.ToRegister(destination), src);
+    } else {
+      __ Str(src, g.ToMemOperand(destination, masm()));
+    }
+  } else if (source->IsStackSlot()) {
+    MemOperand src = g.ToMemOperand(source, masm());
+    DCHECK(destination->IsRegister() || destination->IsStackSlot());
+    if (destination->IsRegister()) {
+      __ Ldr(g.ToRegister(destination), src);
+    } else {
+      UseScratchRegisterScope scope(masm());
+      Register temp = scope.AcquireX();
+      __ Ldr(temp, src);
+      __ Str(temp, g.ToMemOperand(destination, masm()));
+    }
+  } else if (source->IsConstant()) {
+    ConstantOperand* constant_source = ConstantOperand::cast(source);
+    if (destination->IsRegister() || destination->IsStackSlot()) {
+      UseScratchRegisterScope scope(masm());
+      Register dst = destination->IsRegister() ? g.ToRegister(destination)
+                                               : scope.AcquireX();
+      Constant src = g.ToConstant(source);
+      if (src.type() == Constant::kHeapObject) {
+        __ LoadObject(dst, src.ToHeapObject());
+      } else {
+        __ Mov(dst, g.ToImmediate(source));
+      }
+      if (destination->IsStackSlot()) {
+        __ Str(dst, g.ToMemOperand(destination, masm()));
+      }
+    } else if (destination->IsDoubleRegister()) {
+      FPRegister result = g.ToDoubleRegister(destination);
+      __ Fmov(result, g.ToDouble(constant_source));
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      UseScratchRegisterScope scope(masm());
+      FPRegister temp = scope.AcquireD();
+      __ Fmov(temp, g.ToDouble(constant_source));
+      __ Str(temp, g.ToMemOperand(destination, masm()));
+    }
+  } else if (source->IsDoubleRegister()) {
+    FPRegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPRegister dst = g.ToDoubleRegister(destination);
+      __ Fmov(dst, src);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      __ Str(src, g.ToMemOperand(destination, masm()));
+    }
+  } else if (source->IsDoubleStackSlot()) {
+    DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
+    MemOperand src = g.ToMemOperand(source, masm());
+    if (destination->IsDoubleRegister()) {
+      __ Ldr(g.ToDoubleRegister(destination), src);
+    } else {
+      UseScratchRegisterScope scope(masm());
+      FPRegister temp = scope.AcquireD();
+      __ Ldr(temp, src);
+      __ Str(temp, g.ToMemOperand(destination, masm()));
+    }
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AssembleSwap(InstructionOperand* source,
+                                 InstructionOperand* destination) {
+  Arm64OperandConverter g(this, NULL);
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+  if (source->IsRegister()) {
+    // Register-register.
+    UseScratchRegisterScope scope(masm());
+    Register temp = scope.AcquireX();
+    Register src = g.ToRegister(source);
+    if (destination->IsRegister()) {
+      Register dst = g.ToRegister(destination);
+      __ Mov(temp, src);
+      __ Mov(src, dst);
+      __ Mov(dst, temp);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      MemOperand dst = g.ToMemOperand(destination, masm());
+      __ Mov(temp, src);
+      __ Ldr(src, dst);
+      __ Str(temp, dst);
+    }
+  } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
+    UseScratchRegisterScope scope(masm());
+    CPURegister temp_0 = scope.AcquireX();
+    CPURegister temp_1 = scope.AcquireX();
+    MemOperand src = g.ToMemOperand(source, masm());
+    MemOperand dst = g.ToMemOperand(destination, masm());
+    __ Ldr(temp_0, src);
+    __ Ldr(temp_1, dst);
+    __ Str(temp_0, dst);
+    __ Str(temp_1, src);
+  } else if (source->IsDoubleRegister()) {
+    UseScratchRegisterScope scope(masm());
+    FPRegister temp = scope.AcquireD();
+    FPRegister src = g.ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      FPRegister dst = g.ToDoubleRegister(destination);
+      __ Fmov(temp, src);
+      __ Fmov(src, dst);
+      __ Fmov(dst, temp);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      MemOperand dst = g.ToMemOperand(destination, masm());
+      __ Fmov(temp, src);
+      __ Ldr(src, dst);
+      __ Str(temp, dst);
+    }
+  } else {
+    // No other combinations are possible.
+    UNREACHABLE();
+  }
+}
+
+
+void CodeGenerator::AddNopForSmiCodeInlining() { __ movz(xzr, 0); }
+
+
+void CodeGenerator::EnsureSpaceForLazyDeopt() {
+  int space_needed = Deoptimizer::patch_size();
+  if (!linkage()->info()->IsStub()) {
+    // Ensure that we have enough space after the previous lazy-bailout
+    // instruction for patching the code here.
+    intptr_t current_pc = masm()->pc_offset();
+
+    if (current_pc < (last_lazy_deopt_pc_ + space_needed)) {
+      intptr_t padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
+      DCHECK((padding_size % kInstructionSize) == 0);
+      InstructionAccurateScope instruction_accurate(
+          masm(), padding_size / kInstructionSize);
+
+      while (padding_size > 0) {
+        __ nop();
+        padding_size -= kInstructionSize;
+      }
+    }
+  }
+  MarkLazyDeoptSite();
+}
+
+#undef __
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8